<|start_filename|>addon-test-support/-private/serialization/v3.js<|end_filename|>
import { assert } from '@ember/debug';
import { createPactSkeleton, applyBody, serializeMatchingRules, applyMatchingRules } from './utils';

const VERSION = 3;

export default function serializeV3(interaction) {
  let pact = createPactSkeleton(interaction);
  pact.providerStates = interaction.providerStates;

  applyBody(pact.request, interaction.captured.requestBody);
  applyBody(pact.response, interaction.captured.responseText);

  let requestRules = {};
  let responseRules = {};
  for (let matchingRules of interaction.matchingRules || []) {
    serializeRequestRules(matchingRules.request, requestRules);
    serializeResponseRules(matchingRules.response, responseRules);
  }

  applyMatchingRules(pact.request, requestRules);
  applyMatchingRules(pact.response, responseRules);

  return pact;
}

function serializeRequestRules(source, target) {
  if (!source) return;

  normalizeHeaderRules(source);
  serializeRulesForKey(source, target, 'path');
  serializeRulesHashForKey(source, target, 'query');
  serializeRulesHashForKey(source, target, 'header');
  serializeRulesForBody(source, target);
}

function serializeResponseRules(source, target) {
  if (!source) return;

  normalizeHeaderRules(source);
  serializeRulesHashForKey(source, target, 'header');
  serializeRulesForBody(source, target);
}

function normalizeHeaderRules(rules) {
  if (rules.headers) {
    assert('Conflicting matching rules: both `header` and `headers` keys defined', !rules.header);
    rules.header = rules.headers;
    delete rules.headers;
  }
}

function serializeRulesForBody(source, target) {
  if (source.body) {
    target.body = target.body || {};
    Object.assign(target.body, serializeMatchingRules(VERSION, source.body));
  }
}

function serializeRulesForKey(source, target, key) {
  if (source[key]) {
    let rules = serializeMatchingRules(VERSION, source[key]);
    let count = Object.keys(rules).length;
    assert(`Matching rules for ${key} must be for a simple value`, count === 0 || (count === 1 && rules.$));
    target[key] = rules.$;
  }
}

function serializeRulesHashForKey(source, target, key) {
  if (source[key]) {
    target[key] = {};
    for (let childKey of Object.keys(source[key])) {
      serializeRulesForKey(source[key], target[key], childKey);
    }
  }
}


<|start_filename|>addon-test-support/-private/serialization/index.js<|end_filename|>
export { default as serializeMatchingRules } from './utils';
export { default as serializeV2 } from './v2';
export { default as serializeV3 } from './v3';


<|start_filename|>addon-test-support/-private/serialization/v2.js<|end_filename|>
import { assert } from '@ember/debug';
import { createPactSkeleton, applyBody, serializeMatchingRules, applyMatchingRules } from './utils';

const VERSION = 2;

export default function serializeV2(interaction) {
  let pact = createPactSkeleton(interaction);

  applyProviderState(pact, interaction);

  applyBody(pact.request, interaction.captured.requestBody);
  applyBody(pact.response, interaction.captured.responseText);

  let requestRules = {};
  let responseRules = {};
  for (let matchingRules of interaction.matchingRules || []) {
    serializeRequestRules(matchingRules.request, requestRules);
    serializeResponseRules(matchingRules.response, responseRules);
  }

  normalizeMatchingRules(requestRules);
  normalizeMatchingRules(responseRules);

  applyMatchingRules(pact.request, requestRules);
  applyMatchingRules(pact.response, responseRules);

  return pact;
}

function serializeRequestRules(source, target) {
  if (!source) { return; }

  assert('Version 2 of the Pact Specification doesn\'t allow for matching rules for query params', !source.query);

  serializeMatchingRules(VERSION, {
    body: source.body,
    headers: source.headers || source.header,
    path: source.path
  }, '$', target);
}

function serializeResponseRules(source, target) {
  if (!source) { return; }

  serializeMatchingRules(VERSION, {
    body: source.body,
    headers: source.headers || source.header
  }, '$', target);
}

function normalizeMatchingRules(rules) {
  Object.keys(rules).forEach((key) => {
    let matchers = rules[key].matchers;

    assert('Version 2 of the Pact Specification only allows for one matching rule per field', matchers.length < 2);

    if (!matchers.length) {
      delete rules[key];
    } else {
      rules[key] = matchers[0];
    }
  });
}

function applyProviderState(pact, interaction) {
  if (!interaction.providerStates) { return; }

  assert(
    'Version 2 of the Pact Specification only allows for a single provider state per interaction',
    interaction.providerStates.length < 2
  );

  let providerState = interaction.providerStates[0];
  if (!providerState) { return; }

  assert(
    'Version 2 of the Pact Specification doesn\'t allow for parameterized provider states',
    !providerState.params || !Object.keys(providerState.params).length
  );

  pact.providerState = providerState.name;
}


<|start_filename|>addon-test-support/-private/serialization/utils.js<|end_filename|>
import { assert } from '@ember/debug';
import Matcher from 'ember-cli-pact/-private/matcher';

// Generates the base frame for a pact document for either v2 or v3 of the spec
export function createPactSkeleton(interaction) {
  let pact = {
    description: interaction.description,
    request: {
      method: interaction.captured.method,
      headers: interaction.captured.requestHeaders
    },
    response: {
      status: interaction.captured.status,
      headers: interaction.captured.responseHeaders
    }
  };

  extractPathAndQuery(pact, interaction.captured.url);

  return pact;
}

export function applyBody(target, body) {
  if (body) {
    target.body = JSON.parse(body);
  }
}

export function applyMatchingRules(target, rules) {
  if (Object.keys(rules).length) {
    target.matchingRules = rules;
  }
}

export function serializeMatchingRules(version, object, parentPath = '$', root = {}) {
  if (object instanceof Matcher) {
    assert(`The ${object.name} matcher is unavailable in Pact v${version}`, object.availableVersion <= version);
    object.serialize(version, parentPath, root, serializeMatchingRules);
  } else if (Array.isArray(object)) {
    for (let i = 0, len = object.length; i < len; i++) {
      serializeMatchingRules(version, object[i], `${parentPath}[${i}]`, root);
    }
  } else if (object && typeof object === 'object') {
    for (let key of Object.keys(object)) {
      serializeMatchingRules(version, object[key], `${parentPath}.${key}`, root);
    }
  }
  return root;
}

function extractPathAndQuery(pact, url) {
  let questionIndex = url.indexOf('?');
  if (questionIndex !== -1) {
    pact.request.query = parseQuery(url.substring(questionIndex + 1));
    url = url.substring(0, questionIndex);
  }
  pact.request.path = url;
}

function parseQuery(query) {
  let parsed = {};
  for (let item of query.split('&')) {
    let pair = item.split('=');
    let key = decodeURIComponent(pair[0]);
    let value = decodeURIComponent(pair[1]);
    if (parsed[key]) {
      parsed[key].push(value);
    } else {
      parsed[key] = [value];
    }
  }
  return parsed;
}


<|start_filename|>tests/pact/people-v2-provider-mocha-test.js<|end_filename|>
import { describe, it, beforeEach } from 'mocha';
import { setupTest } from 'ember-mocha';
import { setupPact, given, interaction } from 'ember-cli-pact';
import { assert } from 'chai';

describe('Pact | People | v2', function() {
  setupTest({ integration: true });
  setupPact({
    providerName: 'test-v2-provider',
    pactVersion: 2
  });

  beforeEach(function() {
    given('a person exists');
  });

  it('fetching a person by ID', async function() {
    let person = await interaction(() => this.store().findRecord('person', 1));

    assert.equal(person.get('id'), '1');
    assert.equal(person.get('name'), 'Person');
  });
});


<|start_filename|>addon-test-support/mock-provider/mirage.js<|end_filename|>
import require from 'require';
import { assert } from '@ember/debug';
import { camelize } from '@ember/string'
import MockProvider from 'ember-cli-pact/mock-provider';
import { allOf, arrayElements } from 'ember-cli-pact/matchers';

let activeProvider = null;

export default class MirageProvider extends MockProvider {
  constructor() {
    super(...arguments);
    this.server = null;
  }

  startInteraction() {
    super.startInteraction(...arguments);
    this._activate();
    this._startServer();
  }

  addState(name, params) {
    super.addState(...arguments);

    let state = this.lookupProviderState(name);
    assert('Mirage provider states require a callback function', typeof state.config === 'function');
    state.config.call(null, this.server, params);
  }

  endInteraction() {
    this._shutdownServer();
    this._deactivate();
    super.endInteraction(...arguments);
  }

  // Called by the PactEnabled serializer mixin
  recordRequest(request) {
    if (this.isCapturing()) {
      this.interaction.recordRequest(request);
    }
  }

  _activate() {
    assert('Attempted to activate multiple mock Mirage providers at once', !activeProvider);
    activeProvider = this;
  }

  _deactivate() {
    assert('Attempted to shut down a mock Mirage provider that wasn\'t active', activeProvider === this);
    activeProvider = null;
  }

  _startServer() {
    try {
      let { modulePrefix } = this.config;
      let { startMirage } = require(`${modulePrefix}/initializers/ember-cli-mirage`);
      this.server = startMirage();
      this.server.passthrough('/_pact/*path');
    } catch (error) {
      throw new Error(`Unable to start mirage server; is ember-cli-mirage installed? ${error.message}`);
    }
  }

  _shutdownServer() {
    this.server.shutdown();
  }
}

let mode = 'data';

export function PactEnabled(SerializerClass) {
  return class PactEnabledSerializer extends SerializerClass {
    serialize(resource, request) {
      let serialized = super.serialize(...arguments);
      if (activeProvider) {
        mode = 'rules';
        try {
          let requestRules = this.getMatchingRules(request, serialized);
          let bodyRules = super.serialize(...arguments);
          activeProvider.recordRequest(request);
          activeProvider.specifyMatchingRules(this._mergeMatchingRules(requestRules, bodyRules));
        } finally {
          mode = 'data';
        }
      }

      return serialized;
    }

    getHashForResource() {
      if (mode === 'rules') {
        return this.getMatchingRulesForResource(...arguments);
      } else {
        return super.getHashForResource(...arguments);
      }
    }

    getMatchingRules(/* request, serialized */) {
      return {};
    }

    getMatchingRulesForResource(resource) {
      let { matchingRules } = this.schema.modelFor(camelize(resource.modelName)).class;
      if (matchingRules) {
        let normalized = {};
        for (let key of (Object.keys(matchingRules))) {
          normalized[this.keyForAttribute(key)] = matchingRules[key];
        }
        matchingRules = this.isCollection(resource) ? arrayElements(normalized) : normalized;
      }
      return matchingRules;
    }

    _mergeMatchingRules(requestRules, bodyRules) {
      let merged = Object.assign({}, requestRules);
      merged.response = Object.assign({}, merged.response);
      merged.response.body = allOf([merged.response.body, bodyRules].filter(Boolean));
      return merged;
    }
  };
}


<|start_filename|>tests/unit/-private/serialization/v2-test.js<|end_filename|>
import { module, test } from 'qunit';
import serializeV2 from 'ember-cli-pact/-private/serialization/v2';
import { type, regex } from 'ember-cli-pact/matchers';

module('Unit | Serialization | v2', function() {
  test('serializing path and query params', function(assert) {
    let pact = serializeV2({
      captured: { url: '/foo/bar?baz=qux&a=b&a=c' }
    });

    assert.equal(pact.request.path, '/foo/bar');
    assert.deepEqual(pact.request.query, {
      baz: ['qux'],
      a: ['b', 'c']
    });

    pact = serializeV2({
      captured: { url: '/a/b/c' }
    });

    assert.equal(pact.request.path, '/a/b/c');
    assert.equal('query' in pact.request, false);
  });

  test('serializing request method', function(assert) {
    let pact = serializeV2({
      captured: {
        url: '',
        method: 'GET'
      }
    });

    assert.equal(pact.request.method, 'GET');
  });

  test('serializing respone status', function(assert) {
    let pact = serializeV2({
      captured: {
        url: '',
        status: 200
      }
    });

    assert.equal(pact.response.status, 200);
  });

  test('serializing description and provider states', function(assert) {
    let pact = serializeV2({
      captured: { url: '' },
      description: 'my test interaction',
      providerStates: [{ name: 'one', params: {} }]
    });

    assert.equal(pact.description, 'my test interaction');
    assert.deepEqual(pact.providerState, 'one');

    assert.throws(() => serializeV2({
      captured: { url: '' },
      description: 'my test interaction',
      providerStates: [{ name: 'one', params: { foo: true } }]
    }), /parameterized provider state/);

    assert.throws(() => serializeV2({
      captured: { url: '' },
      description: 'my test interaction',
      providerStates: [
        { name: 'one', params: {} },
        { name: 'two', params: {} }
      ]
    }), /single provider state/);
  });

  test('serializing request/response bodies', function(assert) {
    let pact = serializeV2({
      captured: {
        url: '',
        requestBody: '',
        responseText: ''
      }
    });

    assert.equal('body' in pact.request, false);
    assert.equal('body' in pact.response, false);

    pact = serializeV2({
      captured: {
        url: '',
        requestBody: '[1, 2, 3]',
        responseText: '"hello"'
      }
    });

    assert.deepEqual(pact.request.body, [1, 2, 3]);
    assert.deepEqual(pact.response.body, 'hello');
  });

  test('serializing header matching rules', function(assert) {
    let pact = serializeV2({
      captured: { url: '' },
      matchingRules: [{
        request: {
          header: {
            'Accept': type()
          }
        },
        response: {
          // Should accept either `header` or `headers`
          headers: {
            'Content-Type': type()
          }
        }
      }]
    });

    assert.deepEqual(pact.request.matchingRules, {
      '$.headers.Accept': { match: 'type' }
    });

    assert.deepEqual(pact.response.matchingRules, {
      '$.headers.Content-Type': { match: 'type' }
    });
  });

  test('serializing path matching rules', function(assert) {
    let pact = serializeV2({
      captured: { url: '' },
      matchingRules: [{
        request: { path: type() }
      }]
    });

    assert.deepEqual(pact.request.matchingRules, {
      '$.path': { match: 'type' }
    });
  });

  test('serializing query matching rules', function(assert) {
    assert.throws(() => {
      serializeV2({
        captured: { url: '' },
        matchingRules: [{
          request: {
            query: {}
          }
        }]
      });
    }, /matching rules for query params/);
  });

  test('serializing body matching rules', function(assert) {
    let pact = serializeV2({
      captured: { url: '' },
      matchingRules: [
        {
          request: {
            body: {
              foo: [type(), regex(/abc/)]
            }
          }
        },
        {
          response: {
            body: type()
          }
        },
        {
          request: {
            body: {
              bar: type()
            }
          }
        }
      ]
    });

    assert.deepEqual(pact.response.matchingRules, {
      '$.body': { match: 'type' }
    });

    assert.deepEqual(pact.request.matchingRules, {
      '$.body.foo[0]': { match: 'type' },
      '$.body.foo[1]': { match: 'regex', regex: 'abc' },
      '$.body.bar': { match: 'type' }
    });
  });
});


<|start_filename|>tests/helpers/ajax.js<|end_filename|>
// Quick'n'dirty AJAX without using `fetch` (needs Pretender support)
// or `jQuery` (don't want to assume it's around)
export default function ajax(url, { method = 'GET' } = {}) {
  return new Promise((resolve, reject) => {
    let request = new XMLHttpRequest();
    request.onload = () => resolve(JSON.parse(request.responseText));
    request.onerror = () => reject();
    request.open(method, url);
    request.send();
  });
}


<|start_filename|>lib/test-session.js<|end_filename|>
'use strict';

const fs = require('fs-extra');
const stringify = require('json-stable-stringify');
const difference = require('lodash/difference');
const intersection = require('lodash/intersection');
const debug = require('debug')('ember-cli-pact:test-session');
const PactError = require('./pact-error');

module.exports = class TestSession {
  constructor(id, config) {
    this.id = id;
    this.config = config;
    this.providerInteractions = new Map();
    this.finalized = false;
  }

  addInteraction(data) {
    assert(`Can't add new interactions to a finalized session`, !this.finalized);
    assert(`No interaction submitted`, data.interaction);
    assert(`No version submitted`, data.version);
    debug('Adding interaction "%s" for provider "%s"', data.interaction.description, data.provider);

    let interactions = this._interactionsFor(data.version, data.provider);
    interactions.push(data.interaction);
  }

  finalize() {
    assert(`Can't finalize a session twice`, !this.finalized);
    debug('Finalizing test session');
    this.finalized = true;

    if (this.config.mode === 'write') {
      this._writePacts();
    } else {
      this._verifyPacts();
    }
  }

  _writePacts() {
    let target = this.config.pactsDirectory;
    fs.removeSync(target);
    fs.mkdirpSync(target);

    for (let provider of this.providerInteractions.keys()) {
      fs.writeFileSync(`${target}/${provider}.json`, this._pactStringFor(provider));
    }
  }

  _verifyPacts() {
    let failures = [];
    let actualProviders = Array.from(this.providerInteractions.keys());
    let expectedProviders = fs.readdirSync(this.config.pactsDirectory).map(name => name.replace(/\.json$/, ''));

    for (let extra of difference(actualProviders, expectedProviders)) {
      failures.push(`Unexpected pact: ${extra}.json`);
    }

    for (let missing of difference(expectedProviders, actualProviders)) {
      failures.push(`Missing pact: ${missing}.json`);
    }

    for (let provider of intersection(expectedProviders, actualProviders)) {
      let contents = this._pactStringFor(provider);
      if (fs.readFileSync(`${this.config.pactsDirectory}/${provider}.json`, 'utf-8') !== contents) {
        failures.push(`Changed pact: ${provider}.json`);
      }
    }

    if (failures.length) {
      let message = `Verification failed:\n  - ${failures.join('\n  - ')}`;
      throw new PactError(409, message);
    }
  }

  _pactStringFor(provider) {
    let providerRecord = this.providerInteractions.get(provider);
    let interactions = sortInteractions(providerRecord.interactions);
    let pact = makePact(this.config.consumerName, provider, providerRecord.version, interactions);
    return stringify(pact, { space: 2 }) + '\n';
  }

  _interactionsFor(version, provider) {
    let record = this.providerInteractions.get(provider);
    if (!record) {
      this.providerInteractions.set(provider, record = { version, interactions: [] });
    } else if (record.version !== version) {
      throw new PactError(409, `Received conflicting spec versions for provider ${provider}`);
    }
    return record.interactions;
  }
}

function makePact(consumer, provider, version, interactions) {
  return {
    provider: { name: provider },
    consumer: { name: consumer },
    interactions: interactions,
    metadata: {
      'pactSpecification': {
        version: standardizeVersionNumber(version),
      }
    }
  };
}

function sortInteractions(interactions) {
  return interactions.sort((a, b) => {
    assert(`Duplicate interaction name: '${a.description}'`, a.description !== b.description);
    return a.description < b.description ? -1 : 1;
  });
}

function standardizeVersionNumber(version) {
  return `${Number(version).toFixed(1)}.0`;
}

function assert(message, condition) {
  if (!condition) {
    throw new PactError(400, message);
  }
}


<|start_filename|>node-tests/helpers/command.js<|end_filename|>
'use strict';

/*
 * Creates a fake project object for unit tests.
 *
 * @method getProject
 * @private
 */
function getProject(options) {
  options = options || {};

  let root = options.root || 'default-root';
  let pkg = options.pkg || {
    version: '1.0.0'
  };

  return {
    root,
    pkg,
  };
}

/*
 * Creates a context (`this`) for `ember-cli` command to be able to successfully
 * execute and test `run` method.
 *
 * In unit tests, we could simply
 *
 * @method contextFor
 * @protected
 * @param {String} type A name of the command, e.g. 'publish'
 * @param {Object} options Any additional options that needs to be overwritten
 *                         on the command (`project`, etc.)
 */
function contextFor(name, options) {
  options = options || {};

  let command = require(`../../lib/commands/${name}`);
  command.project = getProject(options);
  return command;
}

module.exports = {
  contextFor
}


<|start_filename|>addon/matchers.js<|end_filename|>
import SimpleMatcher from 'ember-cli-pact/-private/matcher/simple';
import TypeMatcher from 'ember-cli-pact/-private/matcher/type';
import RegexMatcher from 'ember-cli-pact/-private/matcher/regex';
import MultiMatcher from 'ember-cli-pact/-private/matcher/multi';
import SubpathMatcher from 'ember-cli-pact/-private/matcher/subpath';

export function type(options) {
  return new TypeMatcher('type', 2, options);
}

export function regex(regex) {
  return new RegexMatcher('regex', 2, regex);
}

export function equality() {
  return new SimpleMatcher('equality', 3, { match: 'equality' });
}

export function integer() {
  return new SimpleMatcher('integer', 3, { match: 'integer' });
}

export function decimal() {
  return new SimpleMatcher('decimal', 3, { match: 'decimal' });
}

export function allOf(matchers) {
  return new MultiMatcher('allOf', 2, undefined /* implicitly AND */, matchers);
}

export function anyOf(matchers) {
  return new MultiMatcher('anyOf', 2, 'OR', matchers);
}

export function arrayElements(object) {
  return new SubpathMatcher('arrayElements', 2, '[*]', object);
}

export function hashValues(object) {
  return new SubpathMatcher('hashValues', 2, '.*', object);
}


<|start_filename|>tests/unit/-private/matching-rules-test.js<|end_filename|>
import { module, test } from 'qunit';
import { serializeMatchingRules } from 'ember-cli-pact/-private/serialization/utils';
import { type, equality, regex, integer, decimal, allOf, anyOf, arrayElements, hashValues } from 'ember-cli-pact/matchers';

module('Unit | matching-rules', function() {
  test('type()', function(assert) {
    assert.throws(() => serializeMatchingRules(1, type()), /type matcher is unavailable in pact v1/i);

    assert.deepEqual(serializeMatchingRules(2, type()), {
      '$': {
        matchers: [{ match: 'type' }]
      }
    });

    assert.deepEqual(serializeMatchingRules(2, type({ min: 3 })), {
      '$': {
        matchers: [{ match: 'type', min: 3 }]
      }
    });

    assert.deepEqual(serializeMatchingRules(2, type({ max: 5 })), {
      '$': {
        matchers: [{ match: 'type', max: 5 }]
      }
    });

    assert.deepEqual(serializeMatchingRules(2, type({ min: 1, max: 10 })), {
      '$': {
        matchers: [{ match: 'type', min: 1, max: 10 }]
      }
    });

    assert.deepEqual(serializeMatchingRules(2, type({ foo: 'bar' })), {
      '$': {
        matchers: [{ match: 'type' }]
      }
    });
  });

  test('equality()', function(assert) {
    assert.throws(() => serializeMatchingRules(2, equality()), /equality matcher is unavailable in pact v2/i);

    assert.deepEqual(serializeMatchingRules(3, equality()), {
      '$': {
        matchers: [{ match: 'equality' }]
      }
    })
  });

  test('regex()', function(assert) {
    assert.throws(() => serializeMatchingRules(1, regex(/abc/)), /regex matcher is unavailable in pact v1/i);

    assert.deepEqual(serializeMatchingRules(2, regex('a(b)c')), {
      '$': {
        matchers: [{ match: 'regex', regex: 'a(b)c' }]
      }
    });

    assert.deepEqual(serializeMatchingRules(2, regex(/a'b/)), {
      '$': {
        matchers: [{ match: 'regex', regex: 'a\'b' }]
      }
    });

    assert.throws(() => regex(/ab/i), /specifying flags/);
    assert.throws(() => regex({}), /RegExp instance or a string/);
  });

  test('integer()', function(assert) {
    assert.throws(() => serializeMatchingRules(2, integer()), /integer matcher is unavailable in pact v2/i);

    assert.deepEqual(serializeMatchingRules(3, integer()), {
      '$': {
        matchers: [{ match: 'integer' }]
      }
    });
  });

  test('decimal()', function(assert) {
    assert.throws(() => serializeMatchingRules(2, decimal()), /decimal matcher is unavailable in pact v2/i);

    assert.deepEqual(serializeMatchingRules(3, decimal()), {
      '$': {
        matchers: [{ match: 'decimal' }]
      }
    });
  });

  test('arrays', function(assert) {
    assert.deepEqual(serializeMatchingRules(3, [type(), equality()]), {
      '$[0]': {
        matchers: [{ match: 'type' }]
      },
      '$[1]': {
        matchers: [{ match: 'equality' }]
      }
    });
  });

  test('objects', function(assert) {
    let rule = {
      a: type(),
      b: equality()
    };

    assert.deepEqual(serializeMatchingRules(3, rule), {
      '$.a': {
        matchers: [{ match: 'type' }]
      },
      '$.b': {
        matchers: [{ match: 'equality' }]
      }
    });
  });

  test('arrayElements()', function(assert) {
    assert.throws(() => serializeMatchingRules(1, arrayElements()), /arrayElements matcher is unavailable in pact v1/i);

    assert.deepEqual(serializeMatchingRules(2, arrayElements(type())), {
      '$[*]': {
        matchers: [{ match: 'type' }]
      }
    });

    assert.deepEqual(serializeMatchingRules(2, arrayElements({ a: regex(/a/), b: type() })), {
      '$[*].a': {
        matchers: [{ match: 'regex', regex: 'a' }]
      },
      '$[*].b': {
        matchers: [{ match: 'type' }]
      }
    });
  });

  test('hashValues()', function(assert) {
    assert.throws(() => serializeMatchingRules(1, hashValues()), /hashValues matcher is unavailable in pact v1/i);

    assert.deepEqual(serializeMatchingRules(2, hashValues(type())), {
      '$.*': {
        matchers: [{ match: 'type' }]
      }
    });

    assert.deepEqual(serializeMatchingRules(2, hashValues({ a: regex(/a/), b: type() })), {
      '$.*.a': {
        matchers: [{ match: 'regex', regex: 'a' }]
      },
      '$.*.b': {
        matchers: [{ match: 'type' }]
      }
    });
  });

  test('allOf()', function(assert) {
    let rule = allOf([type(), regex(/a/)]);

    assert.throws(() => serializeMatchingRules(1, rule), /allOf matcher is unavailable in pact v1/i);

    assert.deepEqual(serializeMatchingRules(3, rule), {
      '$': {
        matchers: [
          { match: 'type' },
          { match: 'regex', regex: 'a' }
        ]
      }
    });
  });

  test('anyOf()', function(assert) {
    let rule = anyOf([integer(), decimal()]);

    assert.throws(() => serializeMatchingRules(1, rule), /anyOf matcher is unavailable in pact v1/i);

    assert.deepEqual(serializeMatchingRules(3, rule), {
      '$': {
        matchers: [
          { match: 'integer' },
          { match: 'decimal' }
        ],
        combine: 'OR'
      }
    });
  });

  test('anyOf()/allOf() combinations', function(assert) {
    assert.deepEqual(serializeMatchingRules(3, allOf([integer(), allOf([type(), equality()])])), {
      '$': {
        matchers: [
          { match: 'integer' },
          { match: 'type' },
          { match: 'equality' }
        ]
      }
    });

    assert.deepEqual(serializeMatchingRules(3, anyOf([equality(), anyOf([integer(), decimal()])])), {
      '$': {
        matchers: [
          { match: 'equality' },
          { match: 'integer' },
          { match: 'decimal' }
        ],
        combine: 'OR'
      }
    });

    assert.throws(() => serializeMatchingRules(3, allOf([integer(), anyOf([type(), equality()])])), /Conflict/);
    assert.throws(() => serializeMatchingRules(3, anyOf([integer(), allOf([type(), equality()])])), /Conflict/);
  });

  test('final boss', function(assert) {
    let rule = {
      animals: allOf([
        type({ min: 1 }),
        arrayElements(allOf([
          hashValues(type()),
          {
            offspring: allOf([
              type({ min: 3 }),
              arrayElements(hashValues(allOf([
                type(),
                {
                  name: equality()
                }
              ])))
            ])
          }
        ]))
      ])
    };

    assert.deepEqual(serializeMatchingRules(3, rule), {
      '$.animals': {
        matchers: [{ match: 'type', min: 1 }]
      },
      '$.animals[*].*': {
        matchers: [{ match: 'type' }]
      },
      '$.animals[*].offspring': {
        matchers: [{ match: 'type', min: 3 }]
      },
      '$.animals[*].offspring[*].*': {
        matchers: [{ match: 'type' }]
      },
      '$.animals[*].offspring[*].*.name': {
        matchers: [{ match: 'equality' }]
       }
    });
  });
});


<|start_filename|>lib/commands/index.js<|end_filename|>
module.exports = {
  'pact:publish': require('./publish')
};


<|start_filename|>tests/pact/people-v2-provider-qunit-test.js<|end_filename|>
import { test, module } from 'qunit';
import { setupTest } from 'ember-qunit';
import { setupPact, given, interaction } from 'ember-cli-pact';

module('Pact | People | v2', function(hooks) {
  setupTest(hooks);
  setupPact(hooks, {
    providerName: 'test-v2-provider',
    pactVersion: 2
  });

  hooks.beforeEach(function() {
    given('a person exists');
  });

  test('fetching a person by ID', async function(assert) {
    let person = await interaction(() => this.store().findRecord('person', 1));

    assert.equal(person.get('id'), '1');
    assert.equal(person.get('name'), 'Person');
  });
});


<|start_filename|>tests/unit/-private/testing/upload-test.js<|end_filename|>
import { module, test } from 'qunit';
import { uploadInteraction } from 'ember-cli-pact/-private/testing/upload';

module('Unit | upload', function() {
  test('a failed upload', function(assert) {
    return uploadInteraction(null, { provider: 'x', version: 'x' })
      .then(() => assert.ok(false, 'upload should have failed'))
      .catch((error) => {
        assert.equal(error.message, '[ember-cli-pact] No interaction submitted');
      });
  });
});
