Skip to content

Commit

Permalink
chore(api): update API to be consistent with Pact Go
Browse files Browse the repository at this point in the history
  • Loading branch information
mefellows committed May 22, 2018
1 parent 4c2c525 commit b0fe39a
Show file tree
Hide file tree
Showing 9 changed files with 383 additions and 356 deletions.
534 changes: 267 additions & 267 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions examples/messages/consumer/message-consumer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import * as sinon from "sinon";
import { like, term } from "../../../src/dsl/matchers";
import { dogApiHandler } from "./dog-handler";

const { MessageConsumer, Message, synchronousBodyHandler } = require("../../../src/pact");
const { MessageConsumerPact, Message, synchronousBodyHandler } = require("../../../src/pact");
const path = require("path");
const expect = chai.expect;

chai.use(chaiAsPromised);

describe("Message consumer tests", () => {
const messagePact = new MessageConsumer({
const messagePact = new MessageConsumerPact({
consumer: "MyJSMessageConsumer",
dir: path.resolve(process.cwd(), "pacts"),
pactfileWriteMode: "update",
Expand Down
7 changes: 4 additions & 3 deletions src/dsl/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export interface Message {
contents: any;
}

// Consumer message handler
export type MessageHandler = (m: Message) => Promise<any>;
export interface MessageHandlers { [name: string]: MessageHandler; }
// Message producer/handlers
export type MessageConsumer = (m: Message) => Promise<any>;
export type MessageProvider = (m: Message) => Promise<any>;
export interface MessageProviders { [name: string]: MessageProvider; }
export interface StateHandlers { [name: string]: (state: string) => Promise<any>; }
6 changes: 2 additions & 4 deletions src/dsl/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @module PactOptions
*/
import { PactfileWriteMode } from "./mockService";
import { MessageHandlers, StateHandlers } from "pact";
import { MessageProviders, StateHandlers } from "pact";

export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";

Expand Down Expand Up @@ -57,8 +57,6 @@ export interface MandatoryPactOptions {
}

export type PactOptionsComplete = PactOptions & MandatoryPactOptions;
// export interface MessageHandlers { [name: string]: (m: Message) => Promise<any>; }
// export interface StateHandlers { [name: string]: (m: Message) => Promise<any>; }

export interface MessageProviderOptions {
// The name of the consumer
Expand All @@ -80,7 +78,7 @@ export interface MessageProviderOptions {
logLevel?: LogLevel;

// Message providers
handlers: MessageHandlers;
messageProviders: MessageProviders;

// Prepare any provider states
stateHandlers?: StateHandlers;
Expand Down
39 changes: 22 additions & 17 deletions src/messageConsumer.spec.ts → src/messageConsumerPact.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* tslint:disable:no-unused-expression no-empty */
import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
import { MessageConsumer, synchronousBodyHandler, asynchronousBodyHandler } from "./messageConsumer";
import { MessageConsumerPact, synchronousBodyHandler, asynchronousBodyHandler } from "./messageConsumerPact";
import { fail } from "assert";
import { Message } from "./dsl/message";
import * as sinon from "sinon";
Expand All @@ -13,10 +13,10 @@ chai.use(chaiAsPromised);
const expect = chai.expect;

describe("MessageConsumer", () => {
let consumer: MessageConsumer;
let consumer: MessageConsumerPact;

beforeEach(() => {
consumer = new MessageConsumer({
consumer = new MessageConsumerPact({
consumer: "myconsumer",
provider: "myprovider",
});
Expand Down Expand Up @@ -56,7 +56,9 @@ describe("MessageConsumer", () => {
.withMetadata({ baz: "bat" });

expect(consumer.json().providerStates).to.be.a("array");
expect(consumer.json().providerStates).to.deep.eq([{ name: "some state" }]);
expect(consumer.json().providerStates).to.deep.eq([
{ name: "some state" },
]);
});
});
describe("when a valid Message has not been constructed", () => {
Expand All @@ -72,24 +74,21 @@ describe("MessageConsumer", () => {
describe("when an empty description has been given", () => {
it("it should throw an error", () => {
expect(() => {
consumer
.expectsToReceive("");
consumer.expectsToReceive("");
}).to.throw(Error);
});
});
describe("when an empty content object has been given", () => {
it("it should throw an error", () => {
expect(() => {
consumer
.withContent({});
consumer.withContent({});
}).to.throw(Error);
});
});
describe("when an empty metadata object has been given", () => {
it("it should throw an error", () => {
expect(() => {
consumer
.withMetadata({});
consumer.withMetadata({});
}).to.throw(Error);
});
});
Expand All @@ -98,14 +97,16 @@ describe("MessageConsumer", () => {
describe("#verify", () => {
describe("when given a valid handler and message", () => {
it("should successfully verify the consumer message", () => {
const stubbedConsumer = new MessageConsumer({
const stubbedConsumer = new MessageConsumerPact({
consumer: "myconsumer",
provider: "myprovider",
});

// Stub out service factory
(stubbedConsumer as any).getServiceFactory = () => {
return { createMessage: (opts: any) => Promise.resolve("message created") };
return {
createMessage: (opts: any) => Promise.resolve("message created"),
};
};

stubbedConsumer
Expand All @@ -114,7 +115,9 @@ describe("MessageConsumer", () => {
.withContent({ foo: "bar" })
.withMetadata({ baz: "bat" });

return expect(stubbedConsumer.verify((m: Message) => Promise.resolve("yay!"))).to.eventually.be.fulfilled;
return expect(
stubbedConsumer.verify((m: Message) => Promise.resolve("yay!")),
).to.eventually.be.fulfilled;
});
});
});
Expand All @@ -137,7 +140,6 @@ describe("MessageConsumer", () => {
});

describe("handler transformers", () => {

describe("#asynchronousbodyHandler", () => {
describe("when given a function that succeeds", () => {
it("should return a Handler object that returns a completed promise", () => {
Expand All @@ -160,7 +162,9 @@ describe("MessageConsumer", () => {
describe("#synchronousbodyHandler", () => {
describe("when given a function that succeeds", () => {
it("should return a Handler object that returns a completed promise", () => {
const failFn = (obj: any) => { /* do nothing! */ };
const failFn = (obj: any) => {
/* do nothing! */
};
const hFn = synchronousBodyHandler(failFn);

return expect(hFn(testMessage)).to.eventually.be.fulfilled;
Expand All @@ -169,13 +173,14 @@ describe("MessageConsumer", () => {

describe("when given a function that throws an Exception", () => {
it("should return a Handler object that returns a rejected promise", () => {
const failFn = (obj: any) => { throw new Error("fail"); };
const failFn = (obj: any) => {
throw new Error("fail");
};
const hFn = synchronousBodyHandler(failFn);

return expect(hFn(testMessage)).to.eventually.be.rejected;
});
});

});
});
});
52 changes: 33 additions & 19 deletions src/messageConsumer.ts → src/messageConsumerPact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
import { isEmpty, cloneDeep } from "lodash";
import { MatcherResult, extractPayload } from "./dsl/matchers";
import { qToPromise } from "./common/utils";
import { Metadata, Message, MessageHandler } from "./dsl/message";
import {
Metadata,
Message,
MessageProvider,
MessageConsumer,
} from "./dsl/message";
import logger from "./common/logger";
import serviceFactory from "@pact-foundation/pact-node";
import { MessageConsumerOptions } from "./dsl/options";
Expand All @@ -18,7 +23,7 @@ interface PactNodeFactory {
* It is the receiver of an interaction, and needs to be able to handle whatever
* request was provided.
*/
export class MessageConsumer {
export class MessageConsumerPact {
// Build up a valid Message object
private state: any = {};

Expand All @@ -39,9 +44,11 @@ export class MessageConsumer {
// Currently only supports a single state
// but the format needs to be v3 compatible for
// basic interoperability
this.state.providerStates = [{
name: providerState,
}];
this.state.providerStates = [
{
name: providerState,
},
];
}

return this;
Expand Down Expand Up @@ -72,7 +79,9 @@ export class MessageConsumer {
*/
public withContent(content: any) {
if (isEmpty(content)) {
throw new Error("You must provide a valid JSON document or primitive for the Message.");
throw new Error(
"You must provide a valid JSON document or primitive for the Message.",
);
}
this.state.contents = content;

Expand All @@ -87,7 +96,9 @@ export class MessageConsumer {
*/
public withMetadata(metadata: Metadata) {
if (isEmpty(metadata)) {
throw new Error("You must provide valid metadata for the Message, or none at all");
throw new Error(
"You must provide valid metadata for the Message, or none at all",
);
}
this.state.metadata = metadata;

Expand All @@ -109,19 +120,23 @@ export class MessageConsumer {
* @param handler A message handler, that must be able to consume the given Message
* @returns {Promise}
*/
public verify(handler: MessageHandler): Promise<any> {
public verify(handler: MessageConsumer): Promise<any> {
logger.info("Verifying message");

return this.validate()
.then(() => handler(extractPayload(cloneDeep(this.state))))
.then(() => qToPromise<string>(this.getServiceFactory().createMessage({
consumer: this.config.consumer,
content: JSON.stringify(this.state),
dir: this.config.dir,
pactFileWriteMode: this.config.pactfileWriteMode,
provider: this.config.provider,
spec: 3,
})));
.then(() =>
qToPromise<string>(
this.getServiceFactory().createMessage({
consumer: this.config.consumer,
content: JSON.stringify(this.state),
dir: this.config.dir,
pactFileWriteMode: this.config.pactfileWriteMode,
provider: this.config.provider,
spec: 3,
}),
),
);
}

/**
Expand All @@ -139,7 +154,6 @@ export class MessageConsumer {
private getServiceFactory(): PactNodeFactory {
return serviceFactory;
}

}

const isMessage = (x: Message | any): x is Message => {
Expand All @@ -150,7 +164,7 @@ const isMessage = (x: Message | any): x is Message => {

// bodyHandler takes a synchronous function and returns
// a wrapped function that accepts a Message and returns a Promise
export function synchronousBodyHandler(handler: (body: any) => any): MessageHandler {
export function synchronousBodyHandler(handler: (body: any) => any): MessageProvider {
return (m: Message): Promise<any> => {
const body = m.contents;

Expand All @@ -168,6 +182,6 @@ export function synchronousBodyHandler(handler: (body: any) => any): MessageHand
// bodyHandler takes an asynchronous (promisified) function and returns
// a wrapped function that accepts a Message and returns a Promise
// TODO: move this into its own package and re-export?
export function asynchronousBodyHandler(handler: (body: any) => Promise<any>): MessageHandler {
export function asynchronousBodyHandler(handler: (body: any) => Promise<any>): MessageProvider {
return (m: Message) => handler(m.contents);
}
Loading

0 comments on commit b0fe39a

Please sign in to comment.