Viktoriia Vlasiuk
01/05/2023, 10:46 AMbody := waveplanner.CreateWavePlanBody{
Waves: []waveplanner.Wave{
{
CutoffTime: "04:00",
FromTime: "10:00",
ToTime: "15:59",
},
{
CutoffTime: "12:00",
FromTime: "16:00",
ToTime: "20:59",
},
{
CutoffTime: "16:00",
FromTime: "21:00",
ToTime: "09:59",
},
},
}
created := waveplanner.CreateWavePlanResponse{
ID: uuid.NewString(),
MfcID: mfc,
CreatedBy: "user-id",
Waves: []waveplanner.WaveItem{
{
ID: uuid.NewString(),
CutoffTime: "04:00",
FromTime: "10:00",
ToTime: "15:59",
Schedules: []waveplanner.ScheduleItem{},
},
{
ID: uuid.NewString(),
CutoffTime: "12:00",
FromTime: "16:00",
ToTime: "20:59",
Schedules: []waveplanner.ScheduleItem{},
},
{
ID: uuid.NewString(),
CutoffTime: "16:00",
FromTime: "21:00",
ToTime: "09:59",
Schedules: []waveplanner.ScheduleItem{},
},
},
}
mockProvider.
AddInteraction().
Given(fmt.Sprintf("retailer %s, mfc %s exists", retailer, mfc)).
UponReceiving(fmt.Sprintf("a request to post wave plan for for retailer %s mfc %s", retailer, mfc)).
WithRequest(http.MethodPost, fmt.Sprintf("/v1/retailers/%s/mfcs/%s/wavePlan", retailer, mfc), func(b *consumer.V4RequestBuilder) {
b.
Headers(matchers.HeadersMatcher{
"X-Env-Type": {matchers.Like("env")},
"X-Token": {matchers.Like("token")},
"Content-Type": {matchers.S("application/json")},
}).
JSONBody(matchers.Like(body))
}).
WillRespondWith(http.StatusCreated, func(repsb *consumer.V4ResponseBuilder) {
repsb.
Headers(matchers.HeadersMatcher{
"Content-Type": {matchers.S("application/json")},
}).
JSONBody(matchers.Like(created))
})
running the test I get pact created, with these matching rules for _request/response bodies_:
"matchingRules": {
"body": {
"$": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
}
},
and of course the pact contains request /response body content.
My question is: does this matchingRule means that on Provider verification stage the request/response body example will be used as a source of expected request format?
Before this I was using the older pact version and used Body: dsl.Like(map[string]interface{}{}) way of describing expected response format, which produced exact matching rules per field.Yousaf Nabi (pactflow.io)
Viktoriia Vlasiuk
01/07/2023, 7:04 PMBody: dsl.Like(map[string]interface{}{
"code": dsl.Term(code, uuidMatcher),
"mfc-id": dsl.Like("D02"),
"complete-at": dsl.Timestamp(),
"started-at": dsl.Timestamp(),
"picked-at": dsl.Timestamp(),
"closed-at": dsl.Timestamp(),
"cutoffs": dsl.EachLike(dsl.Timestamp(), 1),
"status": dsl.Term("SPLIT", "INCOMPLETE|NEW|SPLIT|PROGRESS|COMPLETE"),
"type": dsl.Term("PRELIM", "PRELIM|DELTA"),
"zone": dsl.Term("STORE", "STORE|OSR|MANUAL"),
"total-lines": dsl.Like(10),
"total-lines-complete": dsl.Like(9),
"total-units": dsl.Like(30),
"total-units-picked": dsl.Like(25),
"out-of-stock-units": dsl.Like(1),
}),
generates these matching rules for response body:
"matchingRules": {
"$.body": {
"match": "type"
},
"$.body.closed-at": {
"match": "regex",
"regex": "^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$"
},
"$.body.code": {
"match": "regex",
"regex": "[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}"
},
"$.body.complete-at": {
"match": "regex",
"regex": "^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$"
},
"$.body.cutoffs": {
"min": 1
},
"$.body.cutoffs[*].*": {
"match": "type"
},
"$.body.cutoffs[*]": {
"match": "regex",
"regex": "^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$"
},
"$.body.mfc-id": {
"match": "type"
},
"$.body.out-of-stock-units": {
"match": "type"
},
"$.body.picked-at": {
"match": "regex",
"regex": "^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$"
},
"$.body.started-at": {
"match": "regex",
"regex": "^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$"
},
"$.body.status": {
"match": "regex",
"regex": "INCOMPLETE|NEW|SPLIT|PROGRESS|COMPLETE"
},
"$.body.total-lines": {
"match": "type"
},
"$.body.total-lines-complete": {
"match": "type"
},
"$.body.total-units": {
"match": "type"
},
"$.body.total-units-picked": {
"match": "type"
},
"$.body.type": {
"match": "regex",
"regex": "PRELIM|DELTA"
},
"$.body.zone": {
"match": "regex",
"regex": "STORE|OSR|MANUAL"
}
}
Matt (pactflow.io / pact-js / pact-go)
"$.body": {
"match": "type"
},
Says “recursively check the JSON to ensure it matches the same field types”.
Then every specific matcher overrides that matching cascade, where there is a more specific matcherMatt (pactflow.io / pact-js / pact-go)
Matt (pactflow.io / pact-js / pact-go)
Viktoriia Vlasiuk
01/09/2023, 9:01 AMMatt (pactflow.io / pact-js / pact-go)
F.i., I’ve found that content-type header is added to the request automatically and your service has to have it also, right?Pact must know the content-type, yes, I think that’s true
Matt (pactflow.io / pact-js / pact-go)
Also I still have doubts regarding list matching and optional fields. My response has an array field that may contain some values or may be empty depending on the data. I’m using matchers.ArrayMinLike, but it requires man array length 1. So I ended up having 2 different interactions: one with empty list, the other one with list with some values. Maybe you could suggest another solution here.that’s the solution
Matt (pactflow.io / pact-js / pact-go)
Slackbot
01/09/2023, 11:00 AMViktoriia Vlasiuk
01/12/2023, 8:54 PMWillRespondWith(
dsl.Response{
Status: http.StatusOK,
Headers: dsl.MapMatcher{
"Content-Type": dsl.String("application/json"),
},
Body: dsl.Like(map[string]interface{}{
"code": dsl.Term(code, uuidMatcher),
"closed-at": dsl.Timestamp(),
}),
},
)
generated this part of contract:Viktoriia Vlasiuk
01/12/2023, 8:55 PMWillRespondWith(http.StatusOK, func(b *consumer.V4ResponseBuilder) {
b.
Header("Content-Type", matchers.S("application/json")).
JSONBody(matchers.MapMatcher{
"code": matchers.Term(code, uuidMatcher),
"closed-at": matchers.Timestamp(),
})
},
)
and the contract:Viktoriia Vlasiuk
01/12/2023, 8:56 PM"contentType": "application/json",
"encoded": false
Viktoriia Vlasiuk
01/12/2023, 8:57 PMMatt (pactflow.io / pact-js / pact-go)
Viktoriia Vlasiuk
01/16/2023, 11:47 AMYousaf Nabi (pactflow.io)
Viktoriia Vlasiuk
01/17/2023, 8:42 AMBody: dsl.Like(map[string]interface{}{
"code": dsl.Term(code, uuidMatcher),
"closed-at": dsl.Timestamp(),
}),
and
JSONBody(matchers.MapMatcher{
"code": matchers.Term(code, uuidMatcher),
"closed-at": matchers.Timestamp(),
})
What is the difference in these 2 descriptions?