Skip to content

Commit

Permalink
feat: add flag to enable handling CORS pre-flight requests
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed Sep 28, 2020
1 parent aa6d803 commit 0adb3fc
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 37 deletions.
1 change: 1 addition & 0 deletions examples/v3/e2e/test/consumer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ describe("Pact V3", () => {
consumer: "Matching Service V3",
provider: "Animal Profile Service V3",
dir: path.resolve(process.cwd(), "pacts"),
cors: true
})

before(() =>
Expand Down
35 changes: 33 additions & 2 deletions native/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,27 @@ declare_types! {
let consumer: String = cx.argument::<JsString>(0)?.value();
let provider: String = cx.argument::<JsString>(1)?.value();
let version: String = cx.argument::<JsString>(2)?.value();
let options: Handle<JsObject> = cx.argument::<JsObject>(3)?;

let mut metadata = RequestResponsePact::default_metadata();
metadata.insert("pactJs".to_string(), btreemap!{ "version".to_string() => version.to_string() });
let mut pact_js_metadata = btreemap!{ "version".to_string() => version.to_string() };
let options = options.downcast::<JsObject>().unwrap();
let js_props = options.get_own_property_names(&mut cx).unwrap();
for prop in js_props.to_vec(&mut cx).unwrap() {
let prop_name = prop.downcast::<JsString>().unwrap().value();
let prop_val = options.get(&mut cx, prop_name.as_str()).unwrap();
if let Ok(val) = prop_val.downcast::<JsString>() {
pact_js_metadata.insert(format!("opts:{}", prop_name), val.value());
} else if let Ok(val) = prop_val.downcast::<JsNumber>() {
pact_js_metadata.insert(format!("opts:{}", prop_name), val.value().to_string());
} else if let Ok(val) = prop_val.downcast::<JsBoolean>() {
pact_js_metadata.insert(format!("opts:{}", prop_name), val.value().to_string());
} else {
error!("Ignoring value for from mock server options '{}'", prop_name);
}
}
metadata.insert("pactJs".to_string(), pact_js_metadata);

let pact = RequestResponsePact {
consumer: Consumer { name: consumer },
provider: Provider { name: provider },
Expand Down Expand Up @@ -669,14 +687,27 @@ declare_types! {

method executeTest(mut cx) {
let test_fn = cx.argument::<JsFunction>(0)?;
let options: Handle<JsObject> = cx.argument::<JsObject>(1)?;
let this = cx.this();

let mock_server_config = match options.get(&mut cx, "cors") {
Ok(cors_prop) => match cors_prop.downcast::<JsBoolean>() {
Ok(cors) => {
debug!("Enabling handling of CORS pre-flight requests in the mock server");
MockServerConfig {
cors_preflight: cors.value()
}
},
_ => MockServerConfig::default()
},
_ => MockServerConfig::default()
};
let mock_server_id = Uuid::new_v4().simple().to_string();
let port = {
let guard = cx.lock();
let pact = this.borrow(&guard);
match MANAGER.lock().unwrap()
.start_mock_server(mock_server_id.clone(), pact.clone(), 0, MockServerConfig::default())
.start_mock_server(mock_server_id.clone(), pact.clone(), 0, mock_server_config)
.map(|port| port as i32) {
Ok(port) => port,
Err(err) => panic!(err)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"lint:prettier:ts": "prettier --parser typescript --check \"{src,test,examples}/**/*.ts\"",
"lint:prettier:js": "prettier --check \"{src,test,examples}/**/*.js\"",
"postdist": "npm t",
"predist": "npm run clean && npm run lint && npm run jscpd",
"predist": "npm run clean",
"release": "standard-version -p beta",
"test": "nyc --check-coverage --reporter=html --reporter=text-summary mocha",
"test:examples": "npm run test:e2e-examples && npm run test:jest-examples && npm run test:mocha-examples && npm run test:ava-examples && npm run test:ts-examples && npm run test:message-examples && npm run test:serverless-examples && npm run test:graphql-examples",
Expand Down
75 changes: 53 additions & 22 deletions src/v3/matchers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import * as R from "ramda"
const PactNative = require("../native")

/**
* Pact Matcher
*/
interface Matcher {
"pact:matcher:type": string
"pact:generator:type"?: string
value?: any
}

/**
* Value must match the given template
* @param template Template to base the comparison on
*/
export function like(template: any) {
export function like(template: any): Matcher {
return {
"pact:matcher:type": "type",
value: template,
Expand All @@ -16,19 +25,26 @@ export function like(template: any) {
* Array where each element must match the given template
* @param template Template to base the comparison on
*/
export function eachLike(template: any) {
export function eachLike(template: any): Matcher {
return {
"pact:matcher:type": "type",
value: [template],
}
}

/**
* Like Matcher with a minimum number of required values
*/
interface MinLikeMatcher extends Matcher {
min: number
}

/**
* An array that has to have at least one element and each element must match the given template
* @param template Template to base the comparison on
* @param count Number of examples to generate, defaults to one
*/
export function atLeastOneLike(template: any, count: number = 1) {
export function atLeastOneLike(template: any, count: number = 1): MinLikeMatcher {
return {
min: 1,
"pact:matcher:type": "type",
Expand All @@ -42,7 +58,7 @@ export function atLeastOneLike(template: any, count: number = 1) {
* @param min Minimum number of elements required in the array
* @param count Number of examples to generate, defaults to one
*/
export function atLeastLike(template: any, min: number, count?: number) {
export function atLeastLike(template: any, min: number, count?: number): MinLikeMatcher {
const elements = count || min
if (count && count < min) {
throw new Error(
Expand All @@ -62,13 +78,20 @@ export function atLeastLike(template: any, min: number, count?: number) {
}
}

/**
* Like Matcher with a maximum number of required values
*/
interface MaxLikeMatcher extends Matcher {
max: number
}

/**
* An array that has to have at most the required number of elements and each element must match the given template
* @param template Template to base the comparison on
* @param max Maximum number of elements required in the array
* @param count Number of examples to generate, defaults to one
*/
export function atMostLike(template: any, max: number, count?: number) {
export function atMostLike(template: any, max: number, count?: number): MaxLikeMatcher {
const elements = count || 1
if (count && count > max) {
throw new Error(
Expand Down Expand Up @@ -100,7 +123,7 @@ export function constrainedArrayLike(
min: number,
max: number,
count?: number
) {
): MinLikeMatcher & MaxLikeMatcher {
const elements = count || min
if (count) {
if (count < min) {
Expand Down Expand Up @@ -136,7 +159,7 @@ export function constrainedArrayLike(
* Value must be a boolean
* @param b Boolean example value
*/
export function boolean(b: boolean) {
export function boolean(b: boolean): Matcher {
return {
"pact:matcher:type": "type",
value: b,
Expand All @@ -147,7 +170,7 @@ export function boolean(b: boolean) {
* Value must be an integer (must be a number and have no decimal places)
* @param int Example value. If omitted a random value will be generated.
*/
export function integer(int?: number) {
export function integer(int?: number): Matcher {
if (int) {
return {
"pact:matcher:type": "integer",
Expand All @@ -166,7 +189,7 @@ export function integer(int?: number) {
* Value must be a decimal number (must be a number and have decimal places)
* @param num Example value. If omitted a random value will be generated.
*/
export function decimal(num?: number) {
export function decimal(num?: number): Matcher {
if (num) {
return {
"pact:matcher:type": "decimal",
Expand All @@ -185,7 +208,7 @@ export function decimal(num?: number) {
* Value must be a number
* @param num Example value. If omitted a random integer value will be generated.
*/
export function number(num?: number) {
export function number(num?: number): Matcher {
if (num) {
return {
"pact:matcher:type": "number",
Expand All @@ -204,26 +227,30 @@ export function number(num?: number) {
* Value must be a string
* @param str Example value
*/
export function string(str: string) {
export function string(str: string): Matcher {
return {
"pact:matcher:type": "type",
value: str,
}
}

interface RegexMatcher extends Matcher {
regex: string
}

/**
* Value that must match the given regular expression
* @param pattern Regular Expression to match
* @param str Example value
*/
export function regex(pattern: string, str: string): any
export function regex(pattern: string, str: string): RegexMatcher
/**
* Value that must match the given regular expression
* @param pattern Regular Expression to match
* @param str Example value
*/
export function regex(pattern: RegExp, str: string): any
export function regex(pattern: any, str: string): any {
export function regex(pattern: RegExp, str: string): RegexMatcher
export function regex(pattern: any, str: string): RegexMatcher {
if (pattern instanceof RegExp) {
return {
"pact:matcher:type": "regex",
Expand All @@ -242,19 +269,23 @@ export function regex(pattern: any, str: string): any {
* Value that must be equal to the example. This is mainly used to reset the matching rules which cascade.
* @param value Example value
*/
export function equal(value: any) {
export function equal(value: any): Matcher {
return {
"pact:matcher:type": "equality",
value,
}
}

interface DateTimeMatcher extends Matcher {
format: string
}

/**
* String value that must match the provided datetime format string.
* @param format Datetime format string. See [Java SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html)
* @param example Example value to use. If omitted a value using the current system date and time will be generated.
*/
export function timestamp(format: string, example?: string) {
export function timestamp(format: string, example?: string): DateTimeMatcher {
return datetime(format, example)
}

Expand All @@ -263,7 +294,7 @@ export function timestamp(format: string, example?: string) {
* @param format Datetime format string. See [Java SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html)
* @param example Example value to use. If omitted a value using the current system date and time will be generated.
*/
export function datetime(format: string, example?: string) {
export function datetime(format: string, example?: string): DateTimeMatcher {
return {
"pact:generator:type": "DateTime",
"pact:matcher:type": "timestamp",
Expand All @@ -277,7 +308,7 @@ export function datetime(format: string, example?: string) {
* @param format Time format string. See [Java SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html)
* @param example Example value to use. If omitted a value using the current system time will be generated.
*/
export function time(format: string, example?: string) {
export function time(format: string, example?: string): DateTimeMatcher {
return {
"pact:generator:type": "Time",
"pact:matcher:type": "time",
Expand All @@ -291,7 +322,7 @@ export function time(format: string, example?: string) {
* @param format Date format string. See [Java SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html)
* @param example Example value to use. If omitted a value using the current system date will be generated.
*/
export function date(format: any, example?: string) {
export function date(format: any, example?: string): DateTimeMatcher {
return {
format,
"pact:generator:type": "Date",
Expand All @@ -304,7 +335,7 @@ export function date(format: any, example?: string) {
* Value that must include the example value as a substring.
* @param value String value to include
*/
export function includes(value: string) {
export function includes(value: string): Matcher {
return {
"pact:matcher:type": "include",
value,
Expand All @@ -315,7 +346,7 @@ export function includes(value: string) {
* Value that must be null. This will only match the JSON Null value. For other content types, it will
* match if the attribute is missing.
*/
export function nullValue() {
export function nullValue(): Matcher {
return {
"pact:matcher:type": "null",
}
Expand All @@ -326,7 +357,7 @@ export function nullValue() {
* @param basePath Base path of the URL
* @param pathFragments list of path fragments, can be regular expressions
*/
export function url(basePath: string, pathFragments: Array<any>) {
export function url(basePath: string, pathFragments: Array<any>): RegexMatcher {
let regex = ".*"
let example = basePath
for (let p of pathFragments) {
Expand Down
Loading

0 comments on commit 0adb3fc

Please sign in to comment.