hltech / pact-gen-ts Goto Github PK
View Code? Open in Web Editor NEWGenerate pact contracts using TypeScript type definitions and custom JSDoc tags.
License: MIT License
Generate pact contracts using TypeScript type definitions and custom JSDoc tags.
License: MIT License
Currently when API function with pact-gen-ts docs does not implicitly return, what makes its type Promise, in generated interaction response body is defined as an empty object, e.g.:
API function:
async putApiCall() {
await this.axios.put( `/example`,{id: 1});
}
and generated response in interaction:
"response": {
"status": 204,
"headers": {
"Content-Type": "application/json"
},
"body": {}
},
to be consistent with existing pact specification body property should not be defined in generated pact in this scenario.
Instead of multiple annotations @pact-datetime
, @pact-date
, I suggest that we should have a single annotation @pact-type
(the exact name is up to discussion) with different values.
interface User {
/** @pact-type uuid */
id: string;
/** @pact-type email */
email: string;
}
Some of the values should be renamed to be more precise:
date
-> isoDate
dateTime
-> isoDateTime
Pact-gen-ts does not generate any pacts for TS 4.4 - probably an issue is within ts-morph and analyzing files content. Need further investigation here.
Code responsible for stringifying query params does not give an option to use other arrayFormat than default. This sometimes leads to being unable to generate pacts that reflect the way application calls an endpoint.
I think current API for defining query could be enhanced to something of following format:
/**
* @pact-query
* @query-array-format: comma // optional param, default is unchanged
*/`
const query = {
...
}
What do you guys think about it?
More advanced (optional) task.
Currently, we throw errors for tuples in types, but pact specification describes these types as possible.
TypeScript compiler changes have a huge impact on pact-gen-ts functionality. Due to TS not following semantic versioning it is hard to predict when it might cause issues with pact-gen-ts library.
My suggestion is to test library with different versions of TypeScript - including @next. Example implementation provided here: react-redux gh action with different TS versions.
It could give us quick feedback whether the API changed in upcomfing TypeScript version
When both /** @pact-request-body */
and /** @pact-response-body */
are used in one API function matchingRules are duplicated. Example:
this API function:
async putApiCall() {
/** @pact-request-body */
const sendData= {prop: 1}
const response = await this.axios.put<{ id: number, name: "John" | 'Emily' }[]>(
`/example`,sendData
);
/** @pact-response-body */
const data = response.data;
return data
}
will create this interaction:
{
"request": {
"method": "GET",
"path": "/example",
"headers": {
"X-Client-Number": "12345"
},
"body": {
"prop": 10
},
"matchingRules": {
"$.body.name": {
"match": "regex",
"regex": "John|Emily"
},
"$.body": {
"match": "type"
}
}
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"body": [
{
"id": 10,
"name": "John"
}
],
"matchingRules": {
"$.body.name": {
"match": "regex",
"regex": "John|Emily"
},
"$.body": {
"match": "type"
}
},
"status": 200
},
"description": "putApiCall"
}
where matchingRules for response and request are the same.
Our tool cannot analyze .tsx
files with JSX syntax.
And throw error with any
type when we for example export type from .tsx files.
After typescript upgrade to v4.7 pact-gen-ts doesn't generate json report.
Error: Pact interactions for provider: ... are empty.
@pact-axios
annotation which will generate pact from axios usageWhen API function is defined as arrow function expression:
/**
* @pact
* @pact-method GET
* @pact-path /example
*/
const getExample = () => axios.get('/example')
pact-gen-ts fails with following error:
> pact-gen-ts
InvalidOperationError: A child of the kind Block was expected.
at Object.throwIfNullOrUndefined (C:\Users\hlukafis\projects\payments-in-ui\node_modules\@ts-morph\common\dist\ts-morph-common.js:471:19)
at ArrowFunction.getFirstChildByKindOrThrow (C:\Users\hlukafis\projects\payments-in-ui\node_modules\ts-morph\dist\ts-morph.js:3734:30)
at InteractionCreator.getResponseBodyForApiFunction (C:\Users\hlukafis\projects\payments-in-ui\node_modules\pact-gen-ts\lib\core\interaction-creator.js:73:50)
at InteractionCreator.getInteractionForPactJsDoc (C:\Users\hlukafis\projects\payments-in-ui\node_modules\pact-gen-ts\lib\core\interaction-creator.js:57:43)
at Array.map (<anonymous>)
at InteractionCreator.findAllInteractions (C:\Users\hlukafis\projects\payments-in-ui\node_modules\pact-gen-ts\lib\core\interaction-creator.js:113:31)
at Function.getAllInteractionsInFile (C:\Users\hlukafis\projects\payments-in-ui\node_modules\pact-gen-ts\lib\core\interaction-creator.js:109:61)
at readInteractionsFromFiles (C:\Users\hlukafis\projects\payments-in-ui\node_modules\pact-gen-ts\lib\core\create-pacts.js:51:71)
at createPactForProvider (C:\Users\hlukafis\projects\payments-in-ui\node_modules\pact-gen-ts\lib\core\create-pacts.js:38:35)
at C:\Users\hlukafis\projects\payments-in-ui\node_modules\pact-gen-ts\lib\core\create-pacts.js:28:61
Since we already have @pact-response-body
and @pact-response-header
annotation, the body of the request should be annotated with @pact-request-body
for consistency and to avoid confusion
When generating pacts from example/
the following pact is generated for getPosts
interaction:
{
"request": {
"path": "/api/clients/10/posts",
"method": "GET",
"headers": {},
"query": "booleanField=true&fromDate=2013-02-01",
"matchingRules": {
"$.query.fromDate": {
"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])))?)$"
}
}
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"body": {},
"status": 200
},
"description": "getPosts"
},
The response.body
is empty, even though /** @pact-response-body */
annotation is used in the getPosts
function.
The same issue is present in pact for addNewPost
ignoreReturnFunction
to config file.@pact-ignore-return-function
which we can add for Js Docs comments of function.When API function documented with pact-gen docs returns undefined
or null
, running pact-gen-ts results in [ERROR]: "any" type is not allowed.
Example API function:
async getApiCall() {
await this.axios.get<{ id: number, name: string }[]>(
`/example`
);
return undefined
}
When api function return type/interface contains nested object which itself contains one of the @pact-matcher - whole nested object in body in generated pact is replaced with the last pact-matcher defined. Example definitions and output:
export interface PactMatchersNestedType {
nestedObject: {
/** @pact-matcher hex */
matcher?: string;
}
}
/**
* @pact
* @pact-method GET
* @pact-path /api
*/
export function apiNestedFunction(): PactMatchersNestedType {
return {
nestedObject: {}
};
}
generated interaction looks like this:
"description": "apiNestedFunction",
"request": Object {
"headers": Object {},
"method": "GET",
"path": "/api",
},
"response": Object {
"body": Object {
"nestedObject": "3F",
},
"headers": Object {},
"matchingRules": Object {
"$.body": Object {
"match": "type",
},
"$.body.nestedObject": Object {
"match": "regex",
"regex": "^[0-9a-fA-F]+$",
},
},
"status": 200,
},
where as you can see nestedObject property inside body is replaced with hex from defined pact-matcher.
I've tested a few pact-matchers and this issue happens every time. If more than one pact-matcher is defined then the last one is used.
Marked property can be optional or required, nested object can contain additional optional or required properties not marked with any matcher - with all this cases same issue occurs.
Same issue happens for interface and TS type definition.
Sometimes pact-gen-ts exits with error code 0 while not generating any interactions (for example when using with TypeScript 4.4 - issue tracked here).
I think this should always be treated as an error state with proper message.
If having no interactions with given provider is intentional, we should suggest removing config for this provider entirely.
It is a follow up of a review and implementation of #48 issue.
It is possible to resolve path from axios function call.
const {data} = await axios.get<string>('/api');
Url is always the first argument of axios call. It might take different forms which need to be handled, for example it could be simple string, template string, concatenated string, variable from other module, etc.
The final result of the type sent to function is always string.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.