Code Monkey home page Code Monkey logo

saloon's Introduction

saloon

Persona-Based Test Seeding

Build Status GitHub release Known Vulnerabilities

Are you:

  1. Tired of manually maintaining test data?
  2. Wishing you could reuse seeding logic across projects and test suites?
  3. Needing to speed up and add stability test data generation?
  4. Wanting to build a GUI for generating accounts?

Yeah?! Saloon is the one-stop shop!

What is Saloon?

Saloon is a Javascript library that can generate e2e accounts with enterprise data in mind. All you have to supply is a persona and each of its entity definitions...Saloon will handle the rest.

Saloon works by traversing the persona and asynchronously generating each entity resource according to the entity definition's instructions. Simple! :bowtie:

Other cool stuff:

  • Works with REST and GraphQL
  • Each entity has access to seeded parent data for simple retrieval of id's, auth tokens, etc
  • Expression engine for generating random data
  • Template engine for generating large data sets
  • Automatic retries on failed requests

Usage

  • Import the library.
  • Populate the definition registry
  • Seed with a persona
import saloon from 'saloon';

const definitions = [{
  type: 'restaurant',
  url: 'http://localhost:3000/api/restaurant'
}, {
  type: 'menu',
  url: 'http://localhost:3000/api/menu',
  body: data => ({ restaurantId: data.restaurantId })
}];

const persona = [{
  type: 'restaurant',
  params: {
    name: 'Bobs Burgers',
    owner: 'Bob Belcher',
    address: '123 Abc Rd, Long Island, NY'
  },
  children: [{
    type: 'menu',
    params: {
      name: 'Lunch Menu',
      startTime: '11:00',
      endTime: '14:00'
    }
  }, {
    type: 'menu',
    params: {
      name: 'Dinner Menu',
      startTime: '17:00',
      endTime: '23:00'
    }
  }]
}];

saloon.setDefinitions(definitions);
saloon.seed(persona)
  .then(output => {});

The example above will first seed the restaurant entity, followed by concurrently seeding both lunch and dinner menu entities.

Running the examples

There are two examples provided:

yarn install
yarn run example // A simple example backed by a local, mocked REST API.
yarn run example:graphql // A more complex example involving both REST and GraphQL API's.

Definitions

Definitions tell the seeder information about each resource defined in the persona. Think of each definition as each one of your REST APIs.

  • method (string|function) - HTTP method, defaults to "post"
  • endpoint (string|function) required - Resource URL
  • headers (object|function) - All headers required for the request
  • body (object|function) - Default request body, props can be overridden by the persona (REST ONLY)
  • query (string|function) - GraphQL query string (GRAPHQL ONLY)
  • variables (object|function) - Default GraphQL query/mutation variables (GRAPHQL ONLY)
  • throttle (number|function) - Throttle requests for this definition (some services can't handle concurrent requests)
export default {
  method: 'put', // {string|function} HTTP method for generating resource, defaults to "post".
  endpoint: 'http://localhost:3000/api/user', // {string|function} Resource API endpoint.
  headers: {},
  body: {},
  throttle: 100
};

All definition values can also be functions. This is useful when the endpoint, headers, or body require values from parent resources. The functions will receive a data argument with all parent resource data:

  • data (Object) - A flattened object with all previously seeded data.
export default {
  endpoint: data => `http://localhost:3000/api/user/${data.user.user_id}/return`,
  headers: data => {
    return {
      Authorization: `firmid=${data.firm.firm_id}`
    }
  }
};

Personas

A test suite will have a collection of personas to test different scenarios and use cases. Persona data is modeled as parent-child relationships.

  • type (string) required - Resource type, must have a definition with the same name
  • params (object|string) - Request body OR GraphQL variables
  • children (array) - An array of children resources which will be seeded after the parent is finished.
  • childrenTemplate (object) - A template for dynamically generating children.
  • childrenCount (number) - The number of children to generate, using the template
[
  {
    "type": "user",
    "params": {
      "username": "Homer_Simpson",
      "password": "DuffBeer1",
      "firstName": "Homer",
      "lastName": "Simpson"
    },
    "children": [
      {
        "type": "client"
      }
    ]
  }
]

Templates

As noted above, templates can be used via childrenTemplate and childrenCount to dynamically generate children resources.

[
  {
    "type": "user",
    "childrenCount": "3",
    "childrenTemplate": {
      "type": "client",
      "children": [
        {
          "type": "taxreturn"
        },
        {
          "type": "taxreturn"
        }
      ]
    }
  }
]

Expression Functions

There are number of expression functions available to dynamically generate test data, which can be called using double-braces. Expression functions are only available for REST entities. These functions are especially useful within childrenTemplate blocks. Here are all functions supported, with arguments and their defaults.:

  • {{address()}}
  • {{age()}}
  • {{bool()}}
  • {{ccExpDate()}}
  • {{ccNum(type = null)}}
  • {{company()}}
  • {{country(full = false)}}
  • {{date(american = true, string = true)}}
  • {{dollars(max = 999999999)}}
  • {{domain()}}
  • {{ein()}}
  • {{email(domain = null, timestamp = false)}}
  • {{firstName()}}
  • {{fullName()}}
  • {{gender()}}
  • {{guid(version = 4)}}
  • {{integer(min = -999999999, max = 999999999)}}
  • {{lastName()}}
  • {{paragraph(sentences = 4)}}
  • {{phone(country = 'us', dashes = true)}}
  • {{profession()}}
  • {{ssn(formatted = true)}}
  • {{ssnLastFour()}}
  • {{state(full = false, country = 'us')}}
  • {{url()}}
  • {{year(min = 1900, max = 2100)}}

saloon's People

Contributors

cleverjam avatar dependabot[bot] avatar jeremy-croff avatar jeremycroff avatar jwils0n avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

saloon's Issues

Output - Merge persona params w/ response data

Sometimes, params passed into an API don't get returned (passwords). They still might be useful in the output, though. So instead of simply adding the response to the output, let's merge it on top of the persona params.

Remove `output` object

It's not really necessary and can add extra confusion. Let's just return the entire seeded persona once complete.

Preprocessor is casting params to a wrong datastructure

given the following definition

{
                                        "id": "{{guid()}}",
                                        "type": "client",
                                        "params": {
                                            "firstName": "Ready",
                                            "lastName": "ToFile"
                                        },
                                        "children": [
                                            {
                                                "return": "readyToFile",
                                                "type": "taxreturn",
                                                "params": {
                                                    "data": {
                                                        "s1": {
                                                            "p0": {
                                                                "c1000100006": {
                                                                    "x1000": {
                                                                        "desc": "{{ssn(formatted = true)}}",
                                                                        "importSource": [
                                                                            "isDetailImport"
                                                                        ],
                                                                        "src": "US"
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        ]
                                    }

then the preprocessor formats c1000100006.x1000.importSource to an object :

snippet of the processed payload

"p0": {
        "c1000100006": {
          "x1000": {
            "desc": "408-80-8895",
            "importSource": {
              "0": "isDetailImport"
            },
            "src": "US"
          }
        },

which is both unexpected and incorrect

Retry doesn't seem to work always

(node:49878) UnhandledPromiseRejectionWarning: Error: Request failed with status code 500
    at createError (/Users/jcroff/dev/saloon/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/Users/jcroff/dev/saloon/node_modules/axios/lib/core/settle.js:18:12)
    at IncomingMessage.handleStreamEnd (/Users/jcroff/dev/saloon/node_modules/axios/lib/adapters/http.js:201:11)
    at emitNone (events.js:111:20)
    at IncomingMessage.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickDomainCallback (internal/process/next_tick.js:218:9)
(node:49878) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:49878) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.```

Uniform parsing of expressions

We have ran in to some issues where templates expressions are sensitive to the params.
for example specifying true vs 'true'.

We should solution for a consistent experience for using the expressions in the templates, and increase the friendliness of using and contributing to them.

Handle deeply nested resource params

We are doing a simple Object.assign for extending resource params with the definition body. We need to do a deep extend, just in case we are dealing with more complicated data models.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.