npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ltipton/parkin

v6.6.1

Published

Parse gherkin features and map them to step definitions

Downloads

128

Readme

Parkin

  • Parse gherkin features text and step definition javascript text
  • Allows mapping feature steps to registered step definition and calls their method

Outline

Install

  • With NPM - npm install @ltipton/parkin
  • With Yarn - yarn add @ltipton/parkin

Use

// With esm imports
import { Parkin } from 'parkin'

// With cjs require
const { Parkin } = require('parkin')

// Parkin is a class, so you should create a new instance of it before using
const PK = new Parkin()

API

Parkin

  • <Class> - Manages features, steps, and definitions
  • <Arguments> - Accepts two arguments
    • (Optional) <Object> - World object passed to all step definition calls
    • (Optional) <Object> - Steps object to register steps on initialization

Parkin.parse

  • <Object> - Containing methods for parsing features and definitions

Parkin.parse.feature

  • <Function> - Parses the text content of a feature file (.feature)
  • <Arguments> - Accepts a single argument
    • (REQUIRED) <String> - Feature file text content
  • Returns an object adhering to the feature model spec

Example

// In Node.js
const fs = require('fs') 
const featureContent = fs.readFileSync('path/to/feature/file.feature')

// Returns an array of feature models parsed from the feature content
const featureModels = PK.parse.feature(featureContent)

Parkin.parse.definition

  • <Function> - Parses the text content of a step definition file (.js)
  • <Arguments> - Accepts a single argument
    • (REQUIRED) <String> - Definition text content ( Valid javascript code as text )
  • Returns an object adhering to the definition model spec

Example

// In Node.js
const fs = require('fs') 
const definitionContent = fs.readFileSync('path/to/step/definition.js')

// Returns an array of definition models parsed from the definition content
const definitionModel = PK.parse.definition(definitionContent)

Parkin.Given

  • <Function> - Register method for Given step definitions
  • <Arguments> - Accepts two arguments
    • (REQUIRED) <String> - Match expression string or regex
    • (REQUIRED) <Function> - Method called when a step definition matches a feature step

Example

import { Parkin } from 'parkin'
const PK = new Parkin()

// Register a step definition with expression syntax
PK.Given(`Given match with {expression} syntax`, (expression) => { /* Assertion code */ })

Parkin.When

  • <Function> - Register method for When step definitions
  • <Arguments> - Accepts two arguments
    • (REQUIRED) <String> - Match expression string or regex
    • (REQUIRED) <Function> - Method called when a step definition matches a feature step

Example

import { Parkin } from 'parkin'
const PK = new Parkin()

// Register a step definition with expression syntax
PK.When(`When match with {expression} syntax`, (expression) => { /* Assertion code */ })

Parkin.Then

  • <Function> - Register method for Then step definitions
  • <Arguments> - Accepts two arguments
    • (REQUIRED) <String> - Match expression string or regex
    • (REQUIRED) <Function> - Method called when a step definition matches a feature step

Example

import { Parkin } from 'parkin'
const PK = new Parkin()
// Register a step definition with expression syntax
PK.Then(`Then match with {expression} syntax`, (expression) => { /* Assertion code */ })

Parkin.registerSteps

  • <Function> - Helper to register multiple step definitions at one time
  • (REQUIRED) <Arguments> - Accepts a single <Object>, matching the example below

Example

import { Parkin } from 'parkin'
const PK = new Parkin()
// Accepts an object with properties of the definition types 
PK.registerSteps({
  given: {
    // Register a given step definition with expression syntax
    `I am on {page}`: (page) => { /* ... */ },
    // Register a given step definition with regex syntax
    `/I goto (\S+)$/`: (page) => { /* ... */ },
  },
  // All other properties follow the same format as defined above
  then: { /* ... */ },
  when: { /* ... */ },
})

Parkin.run

  • <Function> - Runs tests using the following steps:
    1. Parses the passed in feature text into a feature model
    • Bypassed if argument is a feature model object
    1. Matches the parsed feature text with registered step definitions
    • Uses the step definitions match property to match with the feature step text
    1. Calls the methods of the matching step definitions
    • Passes in dynamic arguments of the feature step when method is called
    • World object is always the last argument passed to a step definition method
  • <Arguments> - Accepts a single argument
    • (REQUIRED) <String|Object|Array<String|Object>> - Feature text content or parsed feature matching feature model

Parkin.world

  • <Object> - Global config object accessible when parsing features, and within step definitions
  • World properties and values can be defined before and during feature execution
    • During feature parsing, any part of the feature text can be replaced
      • If the $world value does not exist at this time, the text is treated as is
      • See Feature Parsing for more information
    • Step Expression variables can be replaced when a feature is parsed or during execution
      • If the value exists when a feature is parsed, it will be replaced
        • During execution, it will use the replaced value, and not the runtime value of the $world object
        • See Runtime Parsing for setting values during execution
      • For Step Expression variables only
        • If the value does not exist when a feature is parsed
        • It MUST exist during execution or an error will be thrown
        • If it's not a Step Expression variables, and does not exist when the feature is parsed it is ignored

Feature Parsing

  • Features that contain the a text matching $world.* will be mapped to a corresponding world value
    • The * part of $world.*, should be a path on the world object
    • The RegEx looks like this => /(\$:world|\$world)+\.[^"'\s]*/gm
    • Example
        // Parkin world object
        Parkin.world = { app: { url: 'https://my.app.url' } }
        Parkin.parse.feature(`
          Feature Open from World
            # Any part of a features text content can be replaced during the initial parse
            Scenario: Go to $world.app.url
              Given I open the site "$world.app.url"
      
            # If it does not exist, it will be ignored and displayed as is
            Scenario: Render App Name: $world.app.name
              Given the app name is "$world.app.name"
        `)
    • When the above feature is parsed, both instances of $world.app.url will be replaced with https://my.app.url
    • This runs before Step Definitions are matched to Scenario Steps
      • Which means the match text of the Scenario Step would be
        • Given I open the site "https://my.app.url"
      • And a matching Step Definition text would be
        • Given I open the site {string}
    • IMPORTANT - This happens only once, when the feature is initially parsed by Parkin
      • If the values don't exist on the world object, they will be ignored
      • If the text is not a variable of a Scenario Step, it will be treated as normal text content
      • Example
          // Parkin world object
          Parkin.world = { app: {} }
          Parkin.parse.feature(`
            Feature Render App Name
              Scenario: Render the App Name 
                Given the app name is not set
                # "$world.app.name" does not exist on the world, so it will be ignored
                Then $world.app.name will not be replaced
          `)

Runtime Parsing

  • In some cases, a world value should be parsed during execution of a step, and not when the feature is parsed
    • This can be useful in cases where one step sets a value to the world, and it used later in a future step
    • Example
        // Parkin instance world object
        Parkin.world = { app: {} }
        Parkin.parse.feature(`
          Feature Set then Open
            Scenario: Go to my app url
              # Step definition set the world.app.url value to "https://my.app.url"
              Given I set the app url to be "https://my.app.url"
              # Step definition methods first argument becomes "https://my.app.url"
              And I open the site "$:world.app.url"
        `)
    • When the above feature is parsed, The $:world.app.url will be found and replaced to $world.app.url
      • Due to the :, It will NOT try to find the world value.
      • Instead it removes the :, and the match text of the Scenario Step becomes
        • And I open the site "$world.app.url"
      • The matching Step Definition text would be
        • And I open the site {string}
    • When a Scenario Step is matched to Step Definition
      • All variables are parsed from the scenario step and passed to the Step Definition method
      • If the variable value matches $world.*, it will be replaced by the corresponding $world value
        • The * part of $world.*, should be a path on the world object
        • This happens for non-existing $world values and variables defined with $:world when the feature is parsed
      • IMPORTANT - If the value does not exist on the $world, then the Step Definition method throws an error
    • Because this happens at the time of parsing the Scenario Step variables
      • The value from the $world object at the time the step is parsed is used
      • If the same step that references a $world value is used multiple times and the $world value changes,
        • The value passed to the Step Definition method will be the current value
      • This allows dynamically setting values on the world object during the execution of a feature file
        • Example
            // Parkin instance world object
            Parkin.world = { app: {} }
            Parkin.parse.feature(`
              Feature: Set then Open
                Scenario: Go to my app url
                  # Step definition set the world.app.url value to "https://my.app.url"
                  Given I set the app url to be "https://my.app.url"
                  # Step definition methods first argument becomes "https://my.app.url"
                  And I open the site "$:world.app.url"
                Scenario: Go to google
                  # Step definition set the world.app.url value to "https://google.com"
                  Given I set the app url to be "https://google.com"
                  # Step definition methods first argument becomes "https://google.com"
                  And I open the site "$:world.app.url"
            `)
          
            // After the First Scenario finished running
            Parkin.world.app.url === "https://my.app.url"
          
            // After the Second Scenario finished running
            Parkin.world.app.url === "https://google.com"

Alias Parsing

  • Similar to the $world object, Parkin has a shortcut for parsing aliases
  • This is simply a helper to aid in the readability of feature files
  • All aliases must be defined in the $world.$alias object path
  • An alias can then be referenced in a feature file using the name of the alias prefixed by $$
    • Example
        Parkin.world = { $alias: { foo: `bar` } }
        Parkin.parse.feature(`
          Feature: Use Alias Value
            Scenario: Reference an alias value in a step
              # When parsed, "$$foo" will be replaced with the value "bar"
              Given I use the "$$foo" alias from the world.alias object
        `)
  • It the alias key does not exist in the $world.$alias object, it will be ignored

Model Specs

Feature Model

{
  index: <Number> /* Line number within the parse feature text content */
  feature: <String> /* Name of the feature */
  perspective: <Meta> /* Meta information about the feature */
  desire: <Meta> /* Meta information about the feature */
  comments: <Array> [ /* Array of defined Meta Models */
    <Meta> /* Meta Model */
  ]
  reason: <Array> [ /* Array of defined Meta Models */
    <Meta> /* Meta Model */
  ]
  tags: <Array> [ /* Array of defined tags for the feature */
    <String>
  ]
  scenarios: <Array> [ /* Array of defined Scenario Models */
    <Scenario> /* Scenario Model */
  ]
}

Meta Model

{
  content: <String> /* Meta information about the feature */
  index: <Number> /* Line number within the parse feature text content */
}

Scenario Model

{
  index: <Number> /* Line number within the parse feature text content */
  scenario: <String> /* Name of the scenario */
  uuid: <String> /* Id of scenario created at the time it was parsed */
  tags: <Array> /* Array of defined tags for the scenario */
  steps: <Array> [ /* Array of defined Step Models */
    <Step> /* Step Model */
  ]
}

Step Model

{
  index: <Number> /* Line number within the parse feature text content */
  step: <String> /* Text content of the step used to match with definitions */
  type: <String> /* Gherkin definition type ( Given, When, Then, And, But ) */
  uuid: <String> /* Id of step created at the time it was parsed */
}

Definition Model

{
  type: <String> /* Gherkin definition type ( Given, When, Then, And, But ) */
  name: <String> /* Cleaned and formatted string of the match property */
  match: <String> /* Step matching string to match feature steps with definition methods */
  variant: <String> /* Syntax used for defining the match property ( regex || expression ) */
  content: <String> /* Text content of step definition ( Valid javascript code ) */
  method: <Function> /* Method called when the step definition matches a feature step */
}