Giter Site home page Giter Site logo

cog-pardot's Introduction

Pardot Cog

CircleCI

This is a Crank Cog for Pardot, providing steps and assertions for you to validate the state and behavior of your Pardot instance.

Installation

Ensure you have the crank CLI and docker installed and running locally, then run the following. You'll be prompted to enter your Pardot credentials once the Cog is successfully installed.

$ crank cog:install automatoninc/pardot

Note: You can always re-authenticate later.

Usage

Authentication

You will be asked for the following authentication details on installation. To avoid prompts in a CI/CD context, you can provide the same details as environment variables.

Field Install-Time Environment Variable Description
email CRANK_AUTOMATONINC_PARDOT__EMAIL Email address
password CRANK_AUTOMATONINC_PARDOT__PASSWORD Password
userKey CRANK_AUTOMATONINC_PARDOT__USERKEY User key
# Re-authenticate by running this
$ crank cog:auth automatoninc/pardot

API user keys are available in Pardot under {your email address} > Settings in the API User Key row. In accounts with Salesforce User Sync enabled, you must authenticate with a Pardot-only user. SSO users aren't supported.

Steps

Once installed, the following steps will be available for use in any of your Scenario files.

Name (ID) Expression Expected Data
Check Pardot List Membership
(CheckListMembership)
the (?<email>.+) pardot prospect should (?<optInOut>be opted in to|be opted out of|not be a member of) list (?<listId>.+) - email: The Email Address of the Prospect

- optInOut: One of "be opted in to", "be opted out of", or "not be a member of"

- listId: The ID of the Pardot List
Create a Pardot Prospect
(CreateProspect)
create a pardot prospect - prospect: A map of field names to field values
Delete a Pardot Prospect
(DeleteProspect)
delete the (?<email>.+) pardot prospect - email: Email address
Check a field on a Pardot Prospect
(ProspectFieldEquals)
the (?<field>[a-zA-Z0-9_]+) field on pardot prospect (?<email>.+) should (?<operator>be set|not be set|be less than|be greater than|be one of|be|contain|not be one of|not be|not contain) ?(?<expectedValue>.+)? - email: Prospect's email address

- field: Field name to check

- operator: Check Logic (be, not be, contain, not contain, be greater than, be less than, be set, not be set, be one of, or not be one of)

- expectedValue: Expected field value

Development and Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to add or update tests as appropriate.

Setup

  1. Install node.js (v12.x+ recommended)
  2. Clone this repository.
  3. Install dependencies via npm install
  4. Run npm start to validate the Cog works locally (ctrl+c to kill it)
  5. Run crank cog:install --source=local --local-start-command="npm start" to register your local instance of this Cog. You may need to append a --force flag or run crank cog:uninstall automatoninc/pardot if you've already installed the distributed version of this Cog.

Adding/Modifying Steps

Modify code in src/steps and validate your changes by running crank cog:step automatoninc/pardot and selecting your step.

To add new steps, create new step classes in src/steps. Use existing steps as a starting point for your new step(s). Note that you will need to run crank registry:rebuild in order for your new steps to be recognized.

Always add tests for your steps in the test/steps folder. Use existing tests as a guide.

Modifying the API Client or Authentication Details

Modify the ClientWrapper class at src/client/client-wrapper.ts.

  • If you need to add or modify authentication details, see the expectedAuthFields static property.
  • If you need to expose additional logic from the wrapped API client, add a new ublic method to the wrapper class, which can then be called in any step.
  • It's also possible to swap out the wrapped API client completely. You should only have to modify code within this clase to achieve that.

Note that you will need to run crank registry:rebuild in order for any changes to authentication fields to be reflected. Afterward, you can re-authenticate this Cog by running crank cog:auth automatoninc/pardot

Tests and Housekeeping

Tests can be found in the test directory and run like this: npm test. Ensure your code meets standards by running npm run lint.

cog-pardot's People

Contributors

austinelwell99 avatar iameap avatar saludangelito avatar apanaligan avatar amcpanaligan avatar russellbot avatar roanlibelo avatar

Watchers

James Cloos avatar  avatar  avatar

cog-pardot's Issues

Test result shows the actual value and not what user inputs

Repro Steps:

  1. Type crank cog:steps automatoninc/pardot
  2. Select Check a field on a Pardot prospect.
  3. Enter the email address then press Enter.
  4. On another Field name to check, put contain
  5. On the expected value, just put the domain name.
  6. Press enter and check the result

image

Expected Result:
It should display the expected field value and not the actual value.
image

New Step: Create a Pardot Prospect

As a Crank user, I should be able to create a Pardot Prospect via step

Proposed Step Name: Create a Pardot Prospect
Proposed Step Expression: create a pardot prospect

Proposed Step Fields:

  • prospect (type MAP), where keys represent prospect field names as represented in SFDC API

Notes:

Cog should re-authenticate client if API key expires

Repro Steps

  1. Create a test scenario like the one below
scenario: 62 Minute Pardot Test

steps:
- step: When I create a Pardot Prospect
  data:
    prospect:
      email: [email protected]
- waitFor: 3720
  step: Then the email field on Pardot Prospect [email protected] should be [email protected]
- step: Delete the [email protected] Pardot Prospect
  1. Run the scenario

Expected: The scenario to run (for about 62 minutes) and pass.

Actual: The check step results in an error with the following message:

There was a problem creating the Prospect: Error: Invalid API key or user key

^ Note also the wrong error message, referring to the creation of a prospect.

Add unit tests covering Prospect operator field changes

What / Why

Although not necessary to exercise every operator in tests (this should be covered by run-crank/typescript-cog-utilities#5), we should at least cover a few new branches of code and ensure the field is set correctly

Scope / UAT Target

  • Add operator field assertion in "expected step fields" test for Pardot Prospect Check Step
    • Field is set with expected key
    • Field is set to optional
  • Add error outcome assertion when util.compare throws UnknownOperatorError for Pardot Prospect Check Step
  • Add error outcome assertion when util.compare throws InvalidOperandError for Pardot Prospect Check Step

Set up API client and authentication

Problem / motivation

Naturally, we will not be able to achieve much without the ability to authenticate with Pardot.

Scope / UAT Target

  • Client Wrapper should wrap an API client that uses v4 of the Pardot API.
  • User should be able to authenticate with the following details:
    • Email address - email address of user account
    • Password - password of user account
    • User Key - 32 character hexadecimal user key for user account
  • Error handling (in ClientWrapper constructor, and generally available to steps)
    • Should immediately return an error on failed authentication attempt (error code 15), using an appropriate error message
    • Should immediately return an error when daily API limit is reached (error code 122), using an appropriate error message (e.g. API call limit reached for today.)
    • Should implement retry logic when error code 66 (max concurrent requests reached), up to a a time limit of perhaps 60 seconds.

Proposed Resolution

This fork of an existing Pardot API client for v3 looks reasonable for v4: https://www.npmjs.com/package/lew-pardot

Resources

Logic of greater than and less than is swapped

Repro Steps:

  1. Run the yml file.
scenario: Pardot API Test
description: This test the creation and validation of field in Pardot.

steps:
- step: create a pardot prospect
  data:
    prospect:
        first_name: Rosan
        last_name: Angeles
        email: [email protected]
        company: HS Corp
        is_do_not_email: 1
- step: Validate that the email field on Pardot prospect [email protected] should be [email protected]
- step: Validate that the first_name field on Pardot prospect [email protected] should not be Roan
- step: Validate that the last_name field on Pardot prospect [email protected] should contain Angel
- step: Validate that the is_do_not_email field on Pardot prospect [email protected] should be greater than 0
- step: Delete the [email protected] Pardot prospect.

image

Incorrect step name on smooth operator

Repro Steps:

  1. Type crank cog:steps automatoninc/pardot
  2. Select Check a field on a Pardot prospect.
  3. Enter the email address then press Enter.
  4. Check the name of the step. Instead of "Check Logic". It's still display as "Field name to check"

Pardot:
image

SalesForce:
image

Expected Result:
Instead of "Check Logic". It's still display as "Field name to check"

Operators should appear on the Check Logic step

Repro Steps:

  1. Type crank cog:step automatoninc/pardot
  2. Select the "Check a field on a Pardot Prospect"
  3. Enter value on the required fields.
  4. Check the "Check Logic"

Expected Result:
It should show the operators just like on SalesForce cog.

SalesFroce:
image

Pardot cog:
image_2019_12_04T07_25_16_281Z

New Step: Check a field on a Pardot Prospect

As a Crank user, I should be able to check a field value on a Pardot Prospect

Proposed Step Name: Check a field on a Pardot Prospect
Proposed Step Expression: the (?<field>[a-zA-Z0-9_]+) field on pardot prospect (?<email>.+) should be (?<expectedValue>.+)

Proposed Step Fields:

  • email (type EMAIL), the email address of the prospect
  • field (type STRING), the API name of the field
  • expectedValue (type ANYSCALAR), field value that is expected

Notes

  • API limit/concurrency error/retry rules should also be applied (see #1)
  • Rather than querying for a prospect, it's possible to use the Client.prospects.readByEmail() method to directly retrieve the object. See: https://www.npmjs.com/package/lew-pardot#prospects

New Step: Check list membership

What / Why

As a Crank user, I should be able to check that a Pardot Prospect is a member of a list and whether or not the Prospect is opted out.

Proposed Step Name: Check Pardot List Membership
Proposed Step Expression: the (?<email>.+) pardot prospect should (?<optInOut>(be opted in to|be opted out of|not be a member of)) list (?<listId>.+)

Proposed Step Fields:

  • email (type EMAIL), the email address of the prospect
  • optInOut (type STRING), one of be opted in to, be opted out of, or not be a member of
  • listId (type NUMERIC), the ID of the pardot list

Proposed Step Records

  • listMembership (type KeyValue, named List Membership), returned regardless of outcome anytime a ListMembership record is found. Guaranteed fields should include:
    • id (type NUMERIC)
    • list_id (type NUMERIC)
    • prospect_id (type NUMERIC)
    • opted_out (type BOOLEAN)
    • created_at (type DATETIME)
    • updated_at (type DATETIME)

Proposed Resolution

  • Load the prospect for the given email address and note its ID.
  • Query list memberships for the given listId and prospectId

Outcomes

  • When optInOut is set to be opted in to
    • If no ListMembership is found, the step should fail: Prospect %s is not a member of list %d.
    • The step should pass if a ListMembership is found and opted_out field is false-y (e.g. not set or false or 0)
    • If the opted_out property is truth-y, the step should fail: Expected prospect %s to be opted in to list %d, but the prospect is opted out.
  • When optInOut is set to be opted out of
    • If no ListMembership is found, the step should fail: Prospect %s is not a member of list %d.
    • The step should pass if a ListMembership is found and opted_out is truth-y (e.g. set to 1).
    • If the opted_out property is false-y, the step should fail: Expected prospect %s to be opted out of list %d, but the prospect is opted in.
  • When the optInOut is set to not be a member of
    • If no ListMembership is found, the step should pass.
    • If a ListMemberShip is found, regardless of its opted_out property, the step should fail: Expected prospect %s to not be a member of list %d, but a list membership was found.
  • In any case, if there is no prospect for the given email address, the step should result in an error: No prospect found for email %s

New Step: Delete a Pardot Prospect

As a Crank user, I should be able to delete a Pardot Prospect via step

Proposed Step Name: Delete a Pardot Prospect
Proposed Step Expression: delete the (?<email>.+) pardot prospect
Proposed Step Fields:

  • email (type EMAIL), the email address of the prospect

Notes

  • API limit/concurrency error/retry rules should also be applied (see #1)
  • Can use the Client.prospects.deleteByEmail()

Description when asking the field name and the field values are the same

Steps To Reproduce:

  1. Type crank cog:steps automatoninc/pardot in cmd
  2. Select the step "Validate a Pardot Prospect field.
  3. Input your email then enter
  4. Add the field name and take note of the description.
  5. Press enter and observe the description when getting the value of the field

image

Actual Result:
Description when asking field name and field values is "A map of field names to field values"

Expected Result:
Description should be changed. It can be the same as other cogs.

  • Field name to check
  • Expected field value

Add operator field to Prospect check step

Problem / Motivation

Currently, field check steps on all objects are limited to simply evaluating equality; it's not possible to make any other assertions about the state of records/objects in the system. This is especially problematic on date fields.

In order to support more test cases, we should add an operator field to all field check steps.
In particular, we should support the following operators:be, not be, contain, not contain, be greater than, be less than

Scope / UAT Target

  • There should be an operator field (type string) listed between the field and expectation fields.
  • The operator field should be marked optional (for backward compatibility)
  • The operator field description should read Check Logic (be, not be, contain, not contain, be greater than, or be less than)
  • The step text should be modified so that should be is replaced with should (?<operator>be less than|be greater than|be|contain|not be|not contain)
  • Field check evaluation logic should follow the following guidelines:
    • be should map to what happens currently (==)
    • not be should map to !=
    • contain should cast both values to string can call .includes()
    • not contain should cast both values to string and call ! .includes()
    • be greater than should map to >
      • For values which conform to a date (e.g. YYYY-MM-DD format), values should be converted to moment.js dates and compared using Moment().isBefore() or .isAfter()
      • For values which conform to a datetime (e.g. YYYY-MM-DDTHH:mm:ss), values should be converted to moment.js dates and compared using .isBefore() or isAfter()
      • For numeric values, if necessary, both values should be cast to numbers (could be int or float) before comparison
      • If either value is non-numeric or does not map to a date or datetime format, an error should be thrown.
  • If a step is executed with no operator value, it should assume the logic for be (==)

Proposed Resolution

We may want to centralize field comparison logic in a method on the BaseStep so that any step could just call this.compare(operator, field, value)

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.