diff --git a/.babelrc b/.babelrc index 30ef458..c11f28a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,7 +1,10 @@ { - "presets": ["env", "flow"], + "presets": ["env", "flow", "stage-0"], "plugins": [ "external-helpers", - "transform-runtime" + "transform-runtime", + ["transform-private", { + "pattern": "^_" + }] ] } diff --git a/.eslintrc.json b/.eslintrc.json index 967b8c8..ab93fe0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -163,7 +163,8 @@ ], "no-undefined": "error", "consistent-return": "off", - "import/extensions": "off" + "import/extensions": "off", + "no-underscore-dangle": "off" }, "env": { "node": true @@ -174,7 +175,40 @@ "rules": { "import/no-extraneous-dependencies": "off", "id-length": "off", - "no-shadow": "off" + "no-shadow": "off", + "flowtype/boolean-style": "off", + "flowtype/define-flow-type": "off", + "flowtype/delimiter-dangle": "off", + "flowtype/generic-spacing": "off", + "flowtype/no-primitive-constructor-types": "off", + "flowtype/no-types-missing-file-annotation": "off", + "flowtype/no-weak-types": "off", + "flowtype/object-type-delimiter": "off", + "flowtype/require-parameter-type": "off", + "flowtype/require-return-type": "off", + "flowtype/require-valid-file-annotation": "off", + "flowtype/semi": "off", + "flowtype/space-after-type-colon": "off", + "flowtype/space-before-generic-bracket": "off", + "flowtype/space-before-type-colon": "off", + "flowtype/type-id-match": "off", + "flowtype/union-intersection-spacing": "off", + "flowtype/use-flow-type": "off", + "flowtype/valid-syntax": "off", + "newline-per-chained-call": [ + "error", + { + "ignoreChainWithDepth": 3 + } + ], + "max-lines": [ + "error", + { + "max": 600, + "skipBlankLines": true, + "skipComments": true + } + ] } } ] diff --git a/Makefile b/Makefile index 9ad3e13..6de5f52 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ lint: # formats your js code with prettier, then lints them with eslint lint-js: - @prettier-eslint 'packages/*/+(src|app|test)/**/*.js' '*.js' --list-different --single-quote --trailing-comma all --write + @prettier-eslint 'packages/*/+(src|app|test)/**/*.js' '*.js' --list-different --single-quote --trailing-comma all --parser flow --write @eslint --cache 'packages/*/+(src|app|test)/**/*.js' '*.js' # formats your markdown files with prettier diff --git a/flow-typed/fakeit-input_vx.x.x.js b/flow-typed/fakeit-input_vx.x.x.js new file mode 100644 index 0000000..0ff124f --- /dev/null +++ b/flow-typed/fakeit-input_vx.x.x.js @@ -0,0 +1,3 @@ +declare module '@fakeit/input' { + declare module.exports: any; +} diff --git a/gulpfile.babel.js b/gulpfile.babel.js index d202614..a8dada5 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -17,12 +17,13 @@ gulp.task('build', () => { return gulp .src(packages, { base }) + .pipe($.sourcemaps.init()) .pipe($.plumber({ errorHandler (err) { $.util.log(err.stack) }, })) - .pipe($.changed('dist', { + .pipe($.changed(base, { transformPath: swapSrcWithDist, })) .pipe(through.obj((file, enc, callback) => { @@ -36,6 +37,7 @@ gulp.task('build', () => { file.path = path.resolve(file.base, swapSrcWithDist(file.relative)) callback(null, file) })) + .pipe($.sourcemaps.write('.')) .pipe(gulp.dest(base)) }) diff --git a/package.json b/package.json index 9052432..9243865 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,11 @@ "babel-core": "^6.26.0", "babel-eslint": "^8.2.1", "babel-plugin-external-helpers": "^6.22.0", + "babel-plugin-transform-private": "~0.1.3", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-env": "^1.6.1", "babel-preset-flow": "^6.23.0", + "babel-preset-stage-0": "~6.24.1", "babel-register": "~6.26.0", "chalk": "~2.3.0", "eslint": "~4.15.0", @@ -48,22 +50,30 @@ "eslint-plugin-import": "~2.8.0", "flow-bin": "^0.63.1", "flow-typed": "2.2.3", + "gulp": "github:gulpjs/gulp#4.0", "gulp-babel": "~7.0.0", "gulp-changed": "~3.2.0", "gulp-cli": "~2.0.0", "gulp-load-plugins": "~1.5.0", "gulp-plumber": "~1.2.0", + "gulp-sourcemaps": "~1.12.1", "gulp-util": "~3.0.8", "gulp-watch": "~5.0.0", "husky": "~0.14.3", "lerna": "^2.7.0", "lint-staged": "~6.0.0", + "lodash": "~4.17.4", + "nyc": "~11.4.1", "prettier": "^1.10.2", "prettier-eslint-cli": "~4.7.0", "through2": "~2.0.3" }, "lint-staged": { - "*.js": ["prettier-eslint --write", "eslint --fix", "git add"], + "*.js": [ + "prettier-eslint --write --parser flow", + "eslint --fix", + "git add" + ], "*.scss": [ "prettier --parser scss --single-quote --write", "stylelint --fix", @@ -72,7 +82,13 @@ "*.md": ["prettier --parser markdown --single-quote --write", "git add"], "*.json": ["prettier --parser json --write", "git add"] }, - "dependencies": { - "gulp": "github:gulpjs/gulp#4.0" + "dependencies": {}, + "ava": { + "files": ["packages/*/test/**/*.test.js"], + "source": [ + "packages/*/dist/**/*", + "packages/*/test/fixtures/**/*", + "packages/*/test/utils.js" + ] } } diff --git a/packages/fakeit-core/package.json b/packages/fakeit-core/package.json index 6df3cc9..4c9e60b 100644 --- a/packages/fakeit-core/package.json +++ b/packages/fakeit-core/package.json @@ -19,11 +19,14 @@ "license": "MIT", "homepage": "https://github.com/bentonam/fakeit#readme", "dependencies": { + "@fakeit/file-loader": "^1.0.0", + "callable-instance": "~1.0.0", "chance": "^1.0.13", "debug": "^3.1.0", "faker": "^4.1.0", - "relieve": "^2.2.1", - "@fakeit/file-loader": "^1.0.0" + "joi": "~13.1.1", + "lodash": "~4.17.4", + "relieve": "^2.2.1" }, "plugins": [ "@fakeit/format-csv", diff --git a/packages/fakeit-core/src/model/index.js b/packages/fakeit-core/src/model/index.js new file mode 100644 index 0000000..dfb96b4 --- /dev/null +++ b/packages/fakeit-core/src/model/index.js @@ -0,0 +1,334 @@ +// @flow + +//// +/// @name @fakeit/core +/// @page fakeit-core +//// + +import { get, merge } from 'lodash' +import joi from 'joi' +import Base from './types/base' +import FakeitArray from './types/array' +import FakeitObject from './types/object' +import { validate } from '../utils' + +function model (): Object { + /// @name Model + /// @description This is base of the fakeit api + // $FlowFixMe + class Model extends Base { + _options: Object + + document: Object + + is_root: boolean + + constructor () { + super() + this.document = {} + + ///# @name _settings + ///# @access private + ///# @description + ///# The object that holds all the model options. This can't be accessed outside of the class + ///# so that it can't be modified without running through validation + ///# @type {object} + this._settings = { + ///# @name _settings.name + ///# @description the name of the model. + ///# @required + ///# @type {string} + name: '', + + ///# @name _settings.key + ///# @description This determins the key used for the document + ///# be derived from the file name it's being used in + ///# @required + ///# @type {string, function} + ///# @note can't be an async function. + key: '', + + ///# @name _settings.dependencies + ///# @description the name of the model. If there isn't a name it will + ///# be derived from the file name it's being used in + ///# @type {array} - This is an array of strings + dependencies: [], + + ///# @name _settings.inputs + ///# @description Any inputs that are required for the generation of the data for the model + ///# @type {object} + ///# The key is what you will use to get the data. + ///# The value can be a string to a file path or a url or an async function + inputs: {}, + + ///# @name _settings.min + ///# @description This is the min number of documents that can potentially get created + ///# @type {number, function} + ///# @note If `_settings.count` is defined then this is ignored + min: 1, + + ///# @name _settings.max + ///# @description This is the max number of documents that can potentially get created + ///# @type {number, function} + ///# @note If `_settings.count` is defined then this is ignored + max: 1000, + + ///# @name _settings.count + ///# @description This is the count for number of documents that will get created + ///# @type {null, number, function} + ///# @markup + ///# count ({ $inputs }) { + ///# // inputs would be `$inputs` to note that it's a dynamic + ///# return $inputs.countries.length + ///# }, + count: null, + + ///# @name _settings.before + ///# @description This function will run 1 time before all the documents are generated + ///# @type {null, function} + ///# @markup + ///# async before (t) { // t stands for context + ///# // Anything that would be set on `context` would be local to this model, + ///# // not other models in other files. This way there's no conflicts with + ///# // other models overwriting variables + ///# t.index = 0 + ///# + ///# // for those that would be curious you would still be able to + ///# // reference the count inside of a `before` function. + ///# t.$count = t.$inputs.countries.length + ///# }, + before: null, + + ///# @name _settings.beforeEach + ///# @description This function will run before each document gets generated + ///# @type {null, function} + ///# @markup + ///# beforeEach (t) { + ///# t.index = t.$chance.integer({ min: 0, max: t.$inputs.countries.length - 1 }) + ///# }, + beforeEach: null, + + ///# @name _settings.after + ///# @description This function will run 1 time before all the documents are generated + ///# @type {null, function} same as `_settings.before` + after: null, + + ///# @name _settings.afterEach + ///# @description This function will run after each document gets generated + ///# @type {null, function} same as `_settings.beforeEach` + afterEach: null, + + ///# @name _settings.seed + ///# @description This is the seed that will be passed to plugins like faker and chance + ///# @type {number, string} + seed: 0, + } + + ///# @name is_root + ///# @description This is to identify that this instance is the root + ///# @type {boolean} + this.is_root = true + + delete this.inner + } + + get settings (): Object { + return this._settings + } + + ///# @name options + ///# @description This function allows you to pass in options for the model + ///# @arg {object} options - The options that are be used on the model + ///# @chainable + options (options: Object): Model { + // to retreive the options use `fakeit.settings` + const schema = joi.object({ + name: joi + .string() + .min(1) + .required(), + key: joi + .alternatives() + .try(joi.string(), joi.func()) + .required(), + dependencies: joi.array() + .items(joi.string()), + inputs: joi + .object() + .pattern( + /.+/g, + joi.alternatives() + .try(joi.string() + .regex(/.+\.[a-z]{1,6}$|^http.+/), joi.func()), + ), + min: joi.number(), + max: joi.number(), + count: joi.alternatives() + .try(null, joi.number(), joi.func()), + before: joi.alternatives() + .try(joi.func(), null), + beforeEach: joi.alternatives() + .try(joi.func(), null), + afterEach: joi.alternatives() + .try(joi.func(), null), + after: joi.alternatives() + .try(joi.func(), null), + seed: joi.alternatives() + .try(joi.number(), joi.string()), + }) + + this._settings = merge(this._settings, validate(options, schema) || {}) + + return this + } + + ///# @name _applyDefaults + ///# @private + ///# @description This sets the current instance onto the class that's passed to it as the model + ///# @arg {class} Schema - The class to apply the defaults to + ///# @chainable + _applyDefaults (Schema: Class): Object { + const schema = new Schema() + schema.model = this + return schema + } + /* eslint-disable newline-per-chained-call */ + ///# @name object + ///# @description This is used to create arrays of fake data + ///# @arg {*} ...args - For each key in the object you pass in you can + ///# pass in data types to items, as well as a `fakeit` specific function, + ///# like `fakeit.object`, `fakeit.build`, etc + ///# + ///# @markup Example + ///# fakeit.object().keys({ foo: '' }) + ///# fakeit.object({ foo: '' }) // shorthand + ///# + ///# @markup Example + ///# // you can pass in a fakeit build function + ///# fakeit.object({ + ///# _id: fakeit.after((t) => `contact_${t.$doc.contact_id}`), + ///# doc_type: 'contact', // static data + ///# channels: [ 'ufp-555555555' ], // static data + ///# contact_id: fakeit.build((t) => t.$chance.guid()), + ///# created_on: fakeit.build((t) => new Date(t.$faker.date.past()).getTime()), + ///# modified_on: fakeit.build((t) => new Date(t.$faker.date.recent()).getTime()), + ///# }) + ///# @chainable + object (...args: Object[]): FakeitObject { + const obj = this._applyDefaults(FakeitObject) + return args.length ? obj.keys(...args) : obj + } + + ///# @name array + ///# @description This is used to create the fake items in the array + ///# @arg {*} ...schemas - you can pass in data types to items, as well + ///# as a `fakeit` specific function, like `fakeit.object`, `fakeit.build`, etc + ///# @chainable + ///# @markup Example + ///# fakeit.array().items([ ... ]) + ///# fakeit.array([ ... ]) // shorthand + ///# @markup Example passing in `fakeit.build` + ///# // you can pass in a fakeit build function + ///# fakeit.array() + ///# .items(fakeit.build((t) => `${t.$faker.name.firstName()} ${t.$faker.name.lastName()}`)) + ///# @markup Example passing in static data + ///# // you can also pass in any js data type + ///# // in this example it will choose a random number of these names between 2 and 6 + ///# fakeit.array() + ///# .items([ + ///# 'T'varisuness King', + ///# 'Davoin Shower-Handel', + ///# 'Hingle McCringleberry', + ///# 'J'Dinkalage Morgoone', + ///# 'Xmus Jaxon Flaxon-Waxon', + ///# 'Quatro Quatro', + ///# 'Shakiraquan T.G.I.F. Carter', + ///# 'T.J. A.J. R.J. Backslashinfourth V', + ///# 'The Player Formerly Known as Mousecop', + ///# ]) + ///# .min(2) + ///# .max(6) + array (...args: Array): FakeitArray { + const obj = this._applyDefaults(FakeitArray) + return args.length ? obj.items(...args) : obj + } + + // these functions are just pointing to the base class and it makes the code cleaner like this + ///# @name before + ///# @description This is used to run a function before the document is generated + ///# @arg {function} - The function to run + ///# @chainable + ///# @markup Example: + ///# export default fakeit + ///# .object({ + ///# foo: fakeit.before((t) => t.$faker.name.firstName()), + ///# }) + before (fn: Function | null = null): Base { + return this._applyDefaults(Base).before(fn) + } + + ///# @name build + ///# @description This is used to run a function to generate the document + ///# @arg {function} - The function to run + ///# @chainable + ///# @markup Example: + ///# fakeit.build((t) => ...), + ///# fakeit((t) => ...) // shorthand + ///# @markup Example: + ///# export default fakeit + ///# .object({ + ///# first_name: fakeit.build((t) => t.$faker.name.firstName()), + ///# last_name: fakeit((t) => t.$faker.name.lastName()) // this does the same thing + ///# }) + build (fn: Function | null = null): Base { + return this._applyDefaults(Base).build(fn) + } + + ///# @name after + ///# @description This is used to run a function to generate the document + ///# @arg {function} - The function to run + ///# @chainable + ///# @markup Example: + ///# export default fakeit + ///# .object({ + ///# first_name: fakeit.build((t) => t.$faker.name.firstName()), + ///# last_name: fakeit.build((t) => t.$faker.name.lastName()), + ///# name: fakeit.after((t) => `${t.$doc.first_name} ${t.$doc.last_name}`), + ///# }) + after (fn: Function | null = null): Base { + return this._applyDefaults(Base).after(fn) + } + ///# @name odds + ///# @description + ///# Running this function is making the current item it's being applied to have x odds + ///# that it will run. If it doesn't run then the key it was being applied to will be `null`. + ///# Basically it's a short hand for this. + ///# ```js + ///# fakeit + ///# .build((t) => { + ///# return t.$chance.bool({ likelihood: 70 }) ? t.$faker.name.lastName() : null + ///# }) + ///# ``` + ///# This is used to run a function to generate the document + ///# @arg {number} number [50] - The odds that the function should run + ///# @chainable + ///# @markup Example: + ///# fakeit + ///# .build((t) => t.$faker.name.lastName()) + ///# .odds(70) + odds (odds: number = 50): Base { + return this._applyDefaults(Base).odds(odds) + } + /* eslint-enable newline-per-chained-call */ + + // @todo probably remove this + ref (ref: string): mixed { + return get(this.document, ref) + } + } + + return new Model() +} + +export default model() +export { model } diff --git a/packages/fakeit-core/src/model/types/array.js b/packages/fakeit-core/src/model/types/array.js new file mode 100644 index 0000000..f557c08 --- /dev/null +++ b/packages/fakeit-core/src/model/types/array.js @@ -0,0 +1,201 @@ +// @flow +/* eslint-disable newline-per-chained-call */ + +import _ from 'lodash' +import joi from 'joi' + +import { validate } from '../../utils' +import Base from './base' + +/// @name Array +/// @page fakeit-core/types +/// @description This is used to create arrays of fake data +export default class FakeitArray extends Base { + constructor () { + super() + ///# @name inner.options.min + ///# @description This is the min number of documents that can potentially get created + ///# @type {number, function} + ///# @note If `options.length` is defined then this is ignored + this.inner.options.min = 1 + + ///# @name inner.options.max + ///# @description This is the max number of documents that can potentially get created + ///# @type {number, function} + ///# @note If `inner.options.count` is defined then this is ignored + this.inner.options.max = 100 + + ///# @name inner.options.length + ///# @description This declares the exact number items in this array + ///# @type {null, number, function} + this.inner.options.length = null + + ///# @name inner.options.unique + ///# @description A function that is used to create a unique array + ///# @type {null, function} + this.inner.options.unique = null + + ///# @name inner.options.filter + ///# @description A function that is used to filter the array + ///# @type {null, function} + this.inner.options.filter = null + + this.inner.value = [] + } + + // eslint-disable-next-line + get schema(): string { + return 'array' + } + + ///# @name items + ///# @description This is used to create the fake items in the array + ///# @arg {*} ...schemas - you can pass in data types to items, as well + ///# as a `fakeit` specific function, like `fakeit.object`, `fakeit.build`, etc + ///# @chainable + ///# @markup Example + ///# // you can pass in a fakeit build function + ///# fakeit.array() + ///# .items(fakeit.build((t) => `${t.$faker.name.firstName()} ${t.$faker.name.lastName()}`)) + ///# @markup Example + ///# // you can also pass in any js data type + ///# // in this example it will choose a random number of these names between 2 and 6 + ///# fakeit.array() + ///# .items([ + ///# 'T'varisuness King', + ///# 'Davoin Shower-Handel', + ///# 'Hingle McCringleberry', + ///# 'J'Dinkalage Morgoone', + ///# 'Xmus Jaxon Flaxon-Waxon', + ///# 'Quatro Quatro', + ///# 'Shakiraquan T.G.I.F. Carter', + ///# 'T.J. A.J. R.J. Backslashinfourth V', + ///# 'The Player Formerly Known as Mousecop', + ///# ]) + ///# .min(2) + ///# .max(6) + items (...schemas: Array): Class { + schemas = validate(schemas, joi.array().items(joi.array().min(1))) + const obj = this.clone() + for (const schema of _.flattenDeep(schemas)) { + obj.inner.value.push(schema) + } + return obj + } + + ///# @name min + ///# @description This declares the min number items in this array + ///# @arg {number} min + ///# @chainable + ///# @note Will not be taken into account if `.length()` is declared + min (min: number): Class { + const obj = this.clone() + if (obj.inner.options.length == null) { + min = validate(min, joi.number().min(0), `min must be a number, you passed in "${min}"`) + obj.inner.options.min = min + + // ensure that the max value is never less than or equal to the min + if (min >= obj.inner.options.max) { + obj.inner.options.max = min + 100 + } + } + return obj + } + + ///# @name min + ///# @description This declares the max number items in this array + ///# @arg {number} max + ///# @chainable + ///# @note Will not be taken into account if `.length()` is declared + max (max: number): Class { + const obj = this.clone() + if (obj.inner.options.length == null) { + obj.inner.options.max = validate( + max, + joi.number().min(obj.inner.options.min + 1), + `max must be a number, you passed in "${max}"`, + ) + } + return obj + } + + ///# @name length + ///# @description This declares the exact number items in this array + ///# @arg {number} length + ///# @chainable + length (length: number | Function): Class { + const obj = this.clone() + obj.inner.options.min = null + obj.inner.options.max = null + obj.inner.options.length = validate( + length, + joi.alternatives().try(null, joi.number(), joi.func()), + `length must be a number or a function, you passed in "${length.toString()}"`, + ) + return obj + } + + ///# @name unique + ///# @description This will convert the array that was generated into a unique array + ///# @arg {null, string, function} unique - The same arguments that + ///# are passed into [_.uniqBy](https://lodash.com/docs/4.17.4#uniqBy) from lodash starting + ///# with the second argument + ///# @chainable + unique (unique: string | Function | null = null): Class { + const obj = this.clone() + unique = validate( + unique, + joi.alternatives().try(null, joi.func(), joi.string()), + 'unique must be null, function, or string. It uses lodash `uniq` or `uniqBy` behind the scenes', + ) + let fn + if (unique == null) { + fn = _.uniq + } else { + fn = (list: Array): Array => _.uniqBy(list, unique) + } + + obj.inner.options.unique = fn + + return obj + } + + ///# @name filter + ///# @description This will filter out any values that you don't want. + ///# It will replace the need for this + ///# ```js + ///# fakeit.array() + ///# .items(fakeit.build((t) => t.$faker.name.firstName()).odds(20)) + ///# .filter() // this is exactly the same thing as this after function + ///# .after((t) => { + ///# // FOR THOSE THAT ONLY SEE ALL CAPS, NO NEED TO DO THIS just use `.filter()` + ///# t.value = _.filter(t.value, (item) => item != null || !Number.isNaN(filter)) + ///# }) + ///# ``` + ///# @arg {function, string, array, object, null} unique [null] - The same arguments that + ///# are passed into [_.filter](https://lodash.com/docs/4.17.4#filter) from lodash starting + ///# with the second argument + ///# The only difference is that if you don't pass anything into the filter function + ///# it will filter out `null`, `undefined`, and `NaN` values + ///# @chainable + filter (filter: Function | string | Array | Object | null = null): Class { + const obj = this.clone() + filter = validate( + filter, + joi + .alternatives() + .try(joi.func(), joi.string(), joi.array().min(1), joi.object().min(1), null), + 'filter must be function, string, array, object, or null. It uses lodash `filter` behind the scenes', + ) + if (filter == null) { + filter = (item: mixed): mixed => item != null && !_.isNaN(item) + } + + // I have no idea what's wrong with flow. It's saying Array isn't a valid type + // $FlowFixMe + const fn = (list: Array): Array => _.filter(list, filter) + + obj.inner.options.filter = fn + return obj + } +} diff --git a/packages/fakeit-core/src/model/types/base.js b/packages/fakeit-core/src/model/types/base.js new file mode 100644 index 0000000..016d200 --- /dev/null +++ b/packages/fakeit-core/src/model/types/base.js @@ -0,0 +1,149 @@ +// @flow + +import { cloneDeep } from 'lodash' +import CallableInstance from 'callable-instance' +import joi from 'joi' + +import { validate } from '../../utils' + +const func_schema = joi.alternatives() + .try(joi.func(), null) + +/// @name Base +/// @page fakeit-core/types +/// @description This is the base class that is applied to the object and array class +export default class Base extends CallableInstance { + functions: Object + + inner: Object + + is_fakeit = true + is_root = false + + model: Object + + constructor () { + super('build') + this.is_root = false + this.inner = { + // this is defined on each class the base is applied to + value: null, + options: { + odds: null, + before: null, + beforeEach: null, + build: null, + after: null, + afterEach: null, + }, + } + } + + // eslint-disable-next-line + get schema(): string { + return 'base' + } + + ///# @name clone + ///# @description This makes a clone of the current instance + ///# @returns {class} the cloned class + ///# @chainable + clone (): Object { + // $FlowFixMe + const obj = Object.create(Object.getPrototypeOf(this)) + obj.is_fakeit = true + obj.model = this.model + obj.inner = cloneDeep(this.inner) + return obj + } + + ///# @name before + ///# @description This is used to run a function before the document is generated + ///# @arg {function} - The function to run + ///# @chainable + ///# @markup Example: + ///# export default fakeit + ///# .object({ + ///# foo: fakeit.before((t) => t.$faker.name.firstName()), + ///# }) + before (fn: Function): Class { + // this validation looks a little weird but it makes the error reporting much better + fn = validate({ before: fn }, joi.object({ before: func_schema })).before + const obj = this.clone() + obj.inner.options.before = fn + return obj + } + + ///# @name build + ///# @description This is used to run a function to generate the document + ///# @arg {function} - The function to run + ///# @chainable + ///# @markup Example: + ///# export default fakeit + ///# .object({ + ///# first_name: fakeit.build((t) => t.$faker.name.firstName()), + ///# last_name: fakeit((t) => t.$faker.name.lastName()) // this does the same thing + ///# }) + build (fn: Function): Class { + // this validation looks a little weird but it makes the error reporting much better + fn = validate({ build: fn }, joi.object({ build: func_schema })).build + const obj = this.clone() + obj.inner.options.build = fn + return obj + } + + ///# @name after + ///# @description This is used to run a function to generate the document + ///# @arg {function} - The function to run + ///# @chainable + ///# @markup Example: + ///# export default fakeit + ///# .object({ + ///# first_name: fakeit.build((t) => t.$faker.name.firstName()), + ///# last_name: fakeit.build((t) => t.$faker.name.lastName()), + ///# name: fakeit.after((t) => `${t.$doc.first_name} ${t.$doc.last_name}`), + ///# }) + after (fn: Function): Class { + // this validation looks a little weird but it makes the error reporting much better + fn = validate({ after: fn }, joi.object({ after: func_schema })).after + const obj = this.clone() + obj.inner.options.after = fn + return obj + } + + ///# @name odds + ///# @description + ///# Running this function is making the current item it's being applied to have x odds + ///# that it will run. If it doesn't run then the key it was being applied to will be `null`. + ///# Basically it's a short hand for this. + ///# ```js + ///# fakeit + ///# .build((t) => { + ///# return t.$chance.bool({ likelihood: 70 }) ? t.$faker.name.lastName() : null + ///# }) + ///# ``` + ///# This is used to run a function to generate the document + ///# @arg {number} number [50] - The odds that the function should run + ///# @chainable + ///# @markup Example: + ///# fakeit + ///# .build((t) => t.$faker.name.lastName()) + ///# .odds(70) + odds (odds: number = 50): Class { + const obj = this.clone() + obj.inner.options.odds = validate( + odds, + joi + .number() + .min(0) + .max(100), + `odds expects a number between 1 and 100, you passed in "${odds}"`, + ) + return obj + } + + run (): Class { + const obj = this.clone() + return obj + } +} diff --git a/packages/fakeit-core/src/model/types/object.js b/packages/fakeit-core/src/model/types/object.js new file mode 100644 index 0000000..b9fad4b --- /dev/null +++ b/packages/fakeit-core/src/model/types/object.js @@ -0,0 +1,45 @@ +// @flow + +import joi from 'joi' +import Base from './base' + +import { validate } from '../../utils' + +/// @name Object +/// @page fakeit-core/types +/// @description This is used to create arrays of fake data +export default class FakeitObject extends Base { + constructor () { + super() + this.inner.value = {} + } + + // eslint-disable-next-line + get schema(): string { + return 'object' + } + + ///# @name keys + ///# @description This is used to create the fake items in an object + ///# @arg {*} ...keys - For each key in the object you pass in you can + ///# pass in data types to items, as well as a `fakeit` specific function, + ///# like `fakeit.object`, `fakeit.build`, etc + ///# @markup Example + ///# // you can pass in a fakeit build function + ///# fakeit.object().keys({ + ///# _id: fakeit.after((t) => `contact_${t.$doc.contact_id}`), + ///# doc_type: 'contact', // static data + ///# channels: [ 'ufp-555555555' ], // static data + ///# contact_id: fakeit.build((t) => t.$chance.guid()), + ///# created_on: fakeit.build((t) => new Date(t.$faker.date.past()).getTime()), + ///# modified_on: fakeit.build((t) => new Date(t.$faker.date.recent()).getTime()), + ///# }) + keys (...keys: Array): Object { + keys = validate(keys, joi.array() + .items(joi.object() + .min(1))) + const obj = this.clone() + Object.assign(obj.inner.value || {}, ...keys) + return obj + } +} diff --git a/packages/fakeit-core/src/utils.js b/packages/fakeit-core/src/utils.js new file mode 100644 index 0000000..0db1da9 --- /dev/null +++ b/packages/fakeit-core/src/utils.js @@ -0,0 +1,30 @@ +// @flow +/* eslint-disable import/prefer-default-export */ + +//// +/// @name Utils +/// @page fakeit-core/utils +//// + +import joi from 'joi' + +/// @name validate +/// @description This is a small utility that is used to run joi validation +/// This allows for consistency in validation +/// @arg {*} obj - The item to validate against +/// @arg {Joi} schema - The joi schema +/// @throws Error if the validation fails +/// @returns {*} Returns the result of the validation of it doesn't fail +/* eslint-disable flowtype/require-return-type */ +// $FlowFixMe +export function validate (obj: mixed, schema: ?Object, message: string) { + const result = joi.validate(obj, schema) + if (result.error) { + if (message) { + result.error.details[0].message = message + } + throw result.error.annotate() + } + + return result.value +} diff --git a/packages/fakeit-core/test/model/index.test.js b/packages/fakeit-core/test/model/index.test.js new file mode 100644 index 0000000..981eb33 --- /dev/null +++ b/packages/fakeit-core/test/model/index.test.js @@ -0,0 +1,460 @@ +import ava from 'ava-spec' +import { isFunction, isPlainObject, isEmpty, isArray } from 'lodash' + +import fakeit, { model } from '../../dist/model' + +const test = ava.group('model:index') + +test.group('options', (test) => { + test('get', (t) => { + t.snapshot(fakeit.options) + t.snapshot(model().options) + }) + test.group('set', (test) => { + test('all valid', (t) => { + t.notThrows(() => { + fakeit.options({ + name: 'something', + key: '_woohoo', + dependencies: [ '../foo/something.js', 'bar' ], + inputs: { + content: 'path/to/some/string.json', + something: 'http://path/to/some/url', + woohoo () {}, + }, + min: 20, + max: 50, + count () {}, + before () {}, + beforeEach () {}, + after () {}, + afterEach () {}, + seed: 'woohoo', + }) + }) + }) + + test.group('invalid', (test) => { + const base = { name: 'name', key: '_id' } + const b = (obj) => Object.assign({}, base, obj) + test('name', (t) => { + const error = t.throws(() => { + fakeit.options({ + name: '', + }) + }) + t.snapshot(error) + }) + test('key', (t) => { + const error = t.throws(() => { + fakeit.options({ + name: 'name', + key: '', + }) + }) + t.snapshot(error) + }) + test('dependencies', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + dependencies: {}, + })) + }) + t.snapshot(error) + }) + test('inputs', (t) => { + const one = t.throws(() => { + fakeit.options(b({ + inputs: { + content: '', + }, + })) + }) + t.snapshot(one) + const two = t.throws(() => { + fakeit.options(b({ + inputs: { + content: '../foo', + }, + })) + }) + t.snapshot(two) + }) + + test('min', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + min () {}, + })) + }) + t.snapshot(error) + }) + test('max', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + max () {}, + })) + }) + t.snapshot(error) + }) + test('before', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + before: '', + })) + }) + t.snapshot(error) + }) + test('beforeEach', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + beforeEach: '', + })) + }) + t.snapshot(error) + }) + test('afterEach', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + afterEach: '', + })) + }) + t.snapshot(error) + }) + test('after', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + after: '', + })) + }) + t.snapshot(error) + }) + test('seed', (t) => { + const error = t.throws(() => { + fakeit.options(b({ + seed () {}, + })) + }) + t.snapshot(error) + }) + }) + }) +}) + +test.group('before', (test) => { + test('model was set correctly', (t) => { + const actual = fakeit.before() + t.truthy(isFunction(actual.model)) + }) + test('inner.options.before was set correctly', (t) => { + const actual = fakeit.before(() => 'woohoo') + t.truthy(isFunction(actual.inner.options.before)) + }) + test("throws when function isn't passed", (t) => { + const error = t.throws(() => { + fakeit.before('something') + }) + t.snapshot(error) + }) +}) + +test.group('build', (test) => { + test('fakeit() and fakeit.build() after the same thing', (t) => { + t.deepEqual(fakeit(), fakeit.build()) + }) + test('model was set correctly', (t) => { + const actual = fakeit.build() + t.truthy(isFunction(actual.model)) + }) + test('inner.options.build was set correctly', (t) => { + const actual = fakeit.build(() => 'woohoo') + t.truthy(isFunction(actual.inner.options.build)) + }) + test("throws when function isn't passed", (t) => { + const error = t.throws(() => { + fakeit.build('something') + }) + t.snapshot(error) + }) +}) + +test.group('after', (test) => { + test('model was set correctly', (t) => { + const actual = fakeit.after() + t.truthy(isFunction(actual.model)) + }) + test('inner.options.after was set correctly', (t) => { + const actual = fakeit.after(() => 'woohoo') + t.truthy(isFunction(actual.inner.options.after)) + }) + test("throws when function isn't passed", (t) => { + const error = t.throws(() => { + fakeit.after('something') + }) + t.snapshot(error) + }) +}) + +test.group('object', (test) => { + test('model was set correctly', (t) => { + const actual = fakeit.object() + t.truthy(isFunction(actual.model)) + }) + test('inner.options.object was set correctly', (t) => { + const expected = { foo: 'bar' } + const actual = fakeit.object(expected) + t.truthy(isPlainObject(actual.inner.value)) + t.falsy(isEmpty(actual.inner.value)) + t.deepEqual(actual.inner.value, expected) + }) + test('fakeit.object().keys() works correctly', (t) => { + const expected = { foo: 'foo', bar: fakeit.build(() => 'woohoo') } + const actual = fakeit.object().keys(expected) + t.truthy(isPlainObject(actual.inner.value)) + t.falsy(isEmpty(actual.inner.value)) + t.deepEqual(actual.inner.value, expected) + }) + test("throws when object isn't passed", (t) => { + const error = t.throws(() => { + fakeit.object(() => 'woohoo') + }) + t.snapshot(error) + }) + test("throws when object is passed but doesn't have any keys", (t) => { + const error = t.throws(() => { + fakeit.object({}) + }) + t.snapshot(error) + }) +}) + +test.group('array', (test) => { + test('model was set correctly', (t) => { + const actual = fakeit.array() + t.truthy(isFunction(actual.model)) + }) + + test('inner.options.array was set correctly', (t) => { + const expected = [ 'woohoo', fakeit.build(() => 'woohoo') ] + const actual = fakeit.array(expected) + t.truthy(isArray(actual.inner.value)) + t.falsy(isEmpty(actual.inner.value)) + t.deepEqual(actual.inner.value, expected) + }) + + test('fakeit.array().items() works correctly', (t) => { + const expected = [ 'woohoo', fakeit.build(() => 'woohoo') ] + const actual = fakeit.array().items(expected) + t.truthy(isArray(actual.inner.value)) + t.falsy(isEmpty(actual.inner.value)) + t.deepEqual(actual.inner.value, expected) + }) + + test("throws when array isn't passed", (t) => { + const error = t.throws(() => { + fakeit.array(() => 'woohoo') + }) + t.snapshot(error) + }) + + test("throws when array is passed but doesn't have any items", (t) => { + const error = t.throws(() => { + fakeit.array([]) + }) + t.snapshot(error) + }) + + test.group('min', (test) => { + test('valid', (t) => { + const actual = fakeit.array([ 'woohoo' ]).min(20) + t.is(actual.inner.options.min, 20) + t.is(actual.inner.options.max, 100) + }) + test('converts max to be 100 more than what was set', (t) => { + const actual = fakeit.array([ 'woohoo' ]).min(200) + t.is(actual.inner.options.min, 200) + t.is(actual.inner.options.max, 300) + }) + + test('invalid', (t) => { + const error = t.throws(() => { + fakeit.array([ 'woohoo' ]).min('asdfasdf') + }) + t.snapshot(error) + }) + }) + + test.group('max', (test) => { + test('valid', (t) => { + const actual = fakeit.array([ 'woohoo' ]).max(200) + + t.is(actual.inner.options.max, 200) + }) + + test('invalid', (t) => { + const error = t.throws(() => { + fakeit.array([ 'woohoo' ]).max('asdfasdf') + }) + t.snapshot(error) + }) + }) + + test.group('length', (test) => { + test('valid number', (t) => { + const actual = fakeit.array([ 'woohoo' ]).length(200) + t.is(actual.inner.options.length, 200) + }) + + test('valid function', (t) => { + const expected = () => 200 + const actual = fakeit.array([ 'woohoo' ]).length(expected) + t.is(actual.inner.options.length, expected) + }) + + test('unsets min and max when length is set', (t) => { + const actual = fakeit + .array([ 'woohoo' ]) + .length(200) + .min(20) + .max(80) + t.is(actual.inner.options.min, null) + t.is(actual.inner.options.max, null) + t.is(actual.inner.options.length, 200) + }) + + test('invalid', (t) => { + const error = t.throws(() => { + fakeit.array([ 'woohoo' ]).length('asdfasdf') + }) + t.snapshot(error) + }) + }) + + test.group('unique', (test) => { + test('valid', (t) => { + const actual = fakeit.array([ 'woohoo' ]).unique() + t.truthy(isFunction(actual.inner.options.unique)) + }) + + test('valid function', (t) => { + const actual = fakeit.array([ 'woohoo' ]).unique(() => true) + t.truthy(isFunction(actual.inner.options.unique)) + t.regex(actual.inner.options.unique.toString(), /\.uniqBy\(list/) + }) + + test('valid string', (t) => { + const actual = fakeit.array([ 'woohoo' ]).unique('woohoo') + t.truthy(isFunction(actual.inner.options.unique)) + t.regex(actual.inner.options.unique.toString(), /\.uniqBy\(list/) + }) + + test('invalid', (t) => { + const error = t.throws(() => { + fakeit.array([ 'woohoo' ]).unique(1000) + }) + t.snapshot(error) + }) + }) + + test.group('filter', (test) => { + test('valid', (t) => { + const actual = fakeit.array([ 'woohoo' ]).filter() + t.truthy(isFunction(actual.inner.options.filter)) + t.deepEqual(actual.inner.options.filter([ 'foo', null ]), [ 'foo' ]) + }) + + test('valid custom', (t) => { + const actual = fakeit.array([ 'woohoo' ]).filter(() => true) + t.truthy(isFunction(actual.inner.options.filter)) + t.regex(actual.inner.options.filter.toString(), /\.filter\(list/) + const expected = [ 'foo', null ] + t.deepEqual(actual.inner.options.filter(expected), expected) + }) + + test('invalid', (t) => { + const error = t.throws(() => { + fakeit.array([ 'woohoo' ]).filter(1000) + }) + t.snapshot(error) + }) + }) +}) + +test.group('odds', (test) => { + test('valid', (t) => { + const actual = fakeit.odds(10) + t.is(actual.inner.options.odds, 10) + }) + test('invalid', (t) => { + t.snapshot(t.throws(() => fakeit.odds(-1))) + t.snapshot(t.throws(() => fakeit.odds(101))) + t.snapshot(t.throws(() => fakeit.odds('woohoo'))) + }) +}) + +test.group('schema', (test) => { + test('object', (t) => { + t.is(fakeit.object().schema, 'object') + }) + test('array', (t) => { + t.is(fakeit.array().schema, 'array') + }) + test('before', (t) => { + t.is(fakeit.before().schema, 'base') + }) + test('build', (t) => { + t.is(fakeit.build().schema, 'base') + }) + test('fakeit', (t) => { + t.is(fakeit().schema, 'base') + }) + test('after', (t) => { + t.is(fakeit.after().schema, 'base') + }) + test('odds', (t) => { + t.is(fakeit.odds().schema, 'base') + }) +}) + +// +// +// test.skip('testing', (t) => { +// const details = fakeit.object({ +// prefix: fakeit((t) => t.$chance.prefix()).odds(5), +// first_name: fakeit.build((t) => t.$faker.name.firstName()), +// middle_name: fakeit((t) => t.$chance.name({ middle: true }).split(' ')[1]).odds(70), +// last_name: fakeit((t) => t.$faker.name.lastName()).odds(70), +// company: fakeit.build((t) => t.$faker.company.companyName()).odds(30), +// job_title: fakeit.build((t) => t.$faker.name.jobTitle()).odds(30), +// dob: fakeit.build((t) => new Date(t.$faker.date.past()).toISOString().split('T')[0]).odds(), +// nickname: fakeit.build((t) => t.$faker.random.word()).odds(10), +// }) +// +// const actual = fakeit +// .options({ +// name: 'Contacts', +// key: '_id', +// min: 1, +// max: 4, +// before () {}, // before any documents get generated +// beforeEach () {}, // before +// }) +// .object({ +// _id: fakeit.after((t) => `contact_${t.document.contact_id}`), +// doc_type: 'contact', +// channels: [ 'ufp-555555555' ], +// contact_id: fakeit.build((t) => t.$chance.guid()), +// created_on: fakeit.build((t) => new Date(t.$faker.date.past()).getTime()), +// modified_on: fakeit.build((t) => new Date(t.$faker.date.recent()).getTime()), +// foo: fakeit +// .array() +// .items(fakeit((t) => t.$faker)) +// .min(1) +// .max(10), +// details, +// }) +// +// console.log('actual:', actual.inner.value._id) +// +// t.pass() +// }) diff --git a/packages/fakeit-core/test/model/snapshots/index.test.js.md b/packages/fakeit-core/test/model/snapshots/index.test.js.md new file mode 100644 index 0000000..cdffdda --- /dev/null +++ b/packages/fakeit-core/test/model/snapshots/index.test.js.md @@ -0,0 +1,283 @@ +# Snapshot report for `packages/fakeit-core/test/model/index.test.js` + +The actual snapshot is saved in `index.test.js.snap`. + +Generated by [AVA](https://ava.li). + +## model:index array length invalid + +> Snapshot 1 + + 'length must be a number or a function, you passed in "asdfasdf"' + +## model:index array max invalid + +> Snapshot 1 + + 'max must be a number, you passed in "asdfasdf"' + +## model:index array min invalid + +> Snapshot 1 + + 'min must be a number, you passed in "asdfasdf"' + +## model:index array throws when array is passed but doesn't have any items + +> Snapshot 1 + + `[␊ + [] [1]␊ + ]␊ + ␊ + [1] "0" must contain at least 1 items` + +## model:index array throws when array isn't passed + +> Snapshot 1 + + `[␊ + () => 'woohoo' [1]␊ + ]␊ + ␊ + [1] "0" must be an array` + +## model:index array unique invalid + +> Snapshot 1 + + 'unique must be null, function, or string. It uses lodash `uniq` or `uniqBy` behind the scenes + +## model:index array filter invalid + +> Snapshot 1 + + 'filter must be function, string, array, object, or null. It uses lodash `filter` behind the scenes + +## model:index after throws when function isn't passed + +> Snapshot 1 + + `{␊ + "after" [1, 2]: "something"␊ + }␊ + ␊ + [1] "after" must be a Function␊ + [2] "after" must be one of [null]` + +## model:index before throws when function isn't passed + +> Snapshot 1 + + `{␊ + "before" [1, 2]: "something"␊ + }␊ + ␊ + [1] "before" must be a Function␊ + [2] "before" must be one of [null]` + +## model:index build throws when function isn't passed + +> Snapshot 1 + + `{␊ + "build" [1, 2]: "something"␊ + }␊ + ␊ + [1] "build" must be a Function␊ + [2] "build" must be one of [null]` + +## model:index object throws when object is passed but doesn't have any keys + +> Snapshot 1 + + `[␊ + {} [1]␊ + ]␊ + ␊ + [1] "0" must have at least 1 children` + +## model:index object throws when object isn't passed + +> Snapshot 1 + + `[␊ + () => 'woohoo' [1]␊ + ]␊ + ␊ + [1] "0" must be an object` + +## model:index options get + +> Snapshot 1 + + Function options {} + +> Snapshot 2 + + Function options {} + +## model:index options set invalid after + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "after" [1, 2]: ""␊ + }␊ + ␊ + [1] "after" must be a Function␊ + [2] "after" must be one of [null]` + +## model:index options set invalid afterEach + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "afterEach" [1, 2]: ""␊ + }␊ + ␊ + [1] "afterEach" must be a Function␊ + [2] "afterEach" must be one of [null]` + +## model:index options set invalid before + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "before" [1, 2]: ""␊ + }␊ + ␊ + [1] "before" must be a Function␊ + [2] "before" must be one of [null]` + +## model:index options set invalid beforeEach + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "beforeEach" [1, 2]: ""␊ + }␊ + ␊ + [1] "beforeEach" must be a Function␊ + [2] "beforeEach" must be one of [null]` + +## model:index options set invalid dependencies + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "dependencies" [1]: {}␊ + }␊ + ␊ + [1] "dependencies" must be an array` + +## model:index options set invalid inputs + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "inputs": {␊ + "content" [1, 2]: ""␊ + }␊ + }␊ + ␊ + [1] "content" is not allowed to be empty␊ + [2] "content" must be a Function` + +> Snapshot 2 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "inputs": {␊ + "content" [1, 2]: "../foo"␊ + }␊ + }␊ + ␊ + [1] "content" with value "../foo" fails to match the required pattern: /.+\\.[a-z]{1,6}$|^http.+/␊ + [2] "content" must be a Function` + +## model:index options set invalid key + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key" [1, 2]: ""␊ + }␊ + ␊ + [1] "key" is not allowed to be empty␊ + [2] "key" must be a Function` + +## model:index options set invalid max + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "max" [1]: "[max() {}]"␊ + }␊ + ␊ + [1] "max" must be a number` + +## model:index options set invalid min + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "min" [1]: "[min() {}]"␊ + }␊ + ␊ + [1] "min" must be a number` + +## model:index options set invalid name + +> Snapshot 1 + + `{␊ + "name" [1]: ""␊ + }␊ + ␊ + [1] "name" is not allowed to be empty` + +## model:index options set invalid seed + +> Snapshot 1 + + `{␊ + "name": "name",␊ + "key": "_id",␊ + "seed" [1, 2]: "[seed() {}]"␊ + }␊ + ␊ + [1] "seed" must be a number␊ + [2] "seed" must be a string + +## model:index odds invalid + +> Snapshot 1 + + 'odds expects a number between 1 and 100, you passed in "-1"' + +> Snapshot 2 + + 'odds expects a number between 1 and 100, you passed in "101"' + +> Snapshot 3 + + 'odds expects a number between 1 and 100, you passed in "woohoo"' diff --git a/packages/fakeit-core/test/model/snapshots/index.test.js.snap b/packages/fakeit-core/test/model/snapshots/index.test.js.snap new file mode 100644 index 0000000..8c46d38 Binary files /dev/null and b/packages/fakeit-core/test/model/snapshots/index.test.js.snap differ diff --git a/packages/fakeit-core/test/model/types/array.test.js b/packages/fakeit-core/test/model/types/array.test.js new file mode 100644 index 0000000..a911095 --- /dev/null +++ b/packages/fakeit-core/test/model/types/array.test.js @@ -0,0 +1,14 @@ +// The majority of the tests for array are in `test/model/index.test.js` +import ava from 'ava-spec' +import { isFunction } from 'lodash' + +import FakeitArray from '../../../dist/model/types/array' + +const test = ava.group('model:types:array') +test('init', (t) => { + const actual = new FakeitArray() + t.truthy(isFunction(actual)) + t.falsy(actual.is_root) + t.truthy(actual.is_fakeit) + t.snapshot(actual.inner) +}) diff --git a/packages/fakeit-core/test/model/types/base.test.js b/packages/fakeit-core/test/model/types/base.test.js new file mode 100644 index 0000000..1b64356 --- /dev/null +++ b/packages/fakeit-core/test/model/types/base.test.js @@ -0,0 +1,14 @@ +// The majority of the tests for base are in `test/model/index.test.js` +import ava from 'ava-spec' +import { isFunction } from 'lodash' + +import Base from '../../../dist/model/types/base' + +const test = ava.group('model:types:base') +test('init', (t) => { + const actual = new Base() + t.truthy(isFunction(actual)) + t.falsy(actual.is_root) + t.truthy(actual.is_fakeit) + t.snapshot(actual.inner) +}) diff --git a/packages/fakeit-core/test/model/types/object.test.js b/packages/fakeit-core/test/model/types/object.test.js new file mode 100644 index 0000000..922fae3 --- /dev/null +++ b/packages/fakeit-core/test/model/types/object.test.js @@ -0,0 +1,14 @@ +// The majority of the tests for object are in `test/model/index.test.js` +import ava from 'ava-spec' +import { isFunction } from 'lodash' + +import FakeitObject from '../../../dist/model/types/object' + +const test = ava.group('model:types:object') +test('init', (t) => { + const actual = new FakeitObject() + t.truthy(isFunction(actual)) + t.falsy(actual.is_root) + t.truthy(actual.is_fakeit) + t.snapshot(actual.inner) +}) diff --git a/packages/fakeit-core/test/model/types/snapshots/array.test.js.md b/packages/fakeit-core/test/model/types/snapshots/array.test.js.md new file mode 100644 index 0000000..b3e27ef --- /dev/null +++ b/packages/fakeit-core/test/model/types/snapshots/array.test.js.md @@ -0,0 +1,26 @@ +# Snapshot report for `packages/fakeit-core/test/model/types/array.test.js` + +The actual snapshot is saved in `array.test.js.snap`. + +Generated by [AVA](https://ava.li). + +## model:types:array init + +> Snapshot 1 + + { + options: { + after: null, + afterEach: null, + before: null, + beforeEach: null, + build: null, + filter: null, + length: null, + max: 100, + min: 1, + odds: null, + unique: null, + }, + value: [], + } diff --git a/packages/fakeit-core/test/model/types/snapshots/array.test.js.snap b/packages/fakeit-core/test/model/types/snapshots/array.test.js.snap new file mode 100644 index 0000000..bd27c76 Binary files /dev/null and b/packages/fakeit-core/test/model/types/snapshots/array.test.js.snap differ diff --git a/packages/fakeit-core/test/model/types/snapshots/base.test.js.md b/packages/fakeit-core/test/model/types/snapshots/base.test.js.md new file mode 100644 index 0000000..945fa12 --- /dev/null +++ b/packages/fakeit-core/test/model/types/snapshots/base.test.js.md @@ -0,0 +1,21 @@ +# Snapshot report for `packages/fakeit-core/test/model/types/base.test.js` + +The actual snapshot is saved in `base.test.js.snap`. + +Generated by [AVA](https://ava.li). + +## model:types:base init + +> Snapshot 1 + + { + options: { + after: null, + afterEach: null, + before: null, + beforeEach: null, + build: null, + odds: null, + }, + value: null, + } diff --git a/packages/fakeit-core/test/model/types/snapshots/base.test.js.snap b/packages/fakeit-core/test/model/types/snapshots/base.test.js.snap new file mode 100644 index 0000000..a664024 Binary files /dev/null and b/packages/fakeit-core/test/model/types/snapshots/base.test.js.snap differ diff --git a/packages/fakeit-core/test/model/types/snapshots/object.test.js.md b/packages/fakeit-core/test/model/types/snapshots/object.test.js.md new file mode 100644 index 0000000..9f8e4e5 --- /dev/null +++ b/packages/fakeit-core/test/model/types/snapshots/object.test.js.md @@ -0,0 +1,21 @@ +# Snapshot report for `packages/fakeit-core/test/model/types/object.test.js` + +The actual snapshot is saved in `object.test.js.snap`. + +Generated by [AVA](https://ava.li). + +## model:types:object init + +> Snapshot 1 + + { + options: { + after: null, + afterEach: null, + before: null, + beforeEach: null, + build: null, + odds: null, + }, + value: {}, + } diff --git a/packages/fakeit-core/test/model/types/snapshots/object.test.js.snap b/packages/fakeit-core/test/model/types/snapshots/object.test.js.snap new file mode 100644 index 0000000..65faf84 Binary files /dev/null and b/packages/fakeit-core/test/model/types/snapshots/object.test.js.snap differ