{"id":13878768,"url":"https://github.com/tuwilof/fitting","last_synced_at":"2025-04-09T09:08:46.441Z","repository":{"id":17057756,"uuid":"81070703","full_name":"tuwilof/fitting","owner":"tuwilof","description":"Library add improve test log for RSpec and WebMock, validate its according to API Blueprint and Open API, show the documentation coverage with log.","archived":false,"fork":false,"pushed_at":"2024-07-09T20:38:47.000Z","size":9997,"stargazers_count":61,"open_issues_count":2,"forks_count":8,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-02T06:08:24.862Z","etag":null,"topics":["api-blueprint","consumer-driven-contracts","coverage","coverage-api","document-driven-development","drafter","json-schema","openapi","openapi3","rspec","swagger","tests-coverage","validation","webmock"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tuwilof.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-06T09:32:39.000Z","updated_at":"2025-02-11T23:04:38.000Z","dependencies_parsed_at":"2024-07-10T01:10:54.536Z","dependency_job_id":null,"html_url":"https://github.com/tuwilof/fitting","commit_stats":{"total_commits":1007,"total_committers":15,"mean_commits":67.13333333333334,"dds":"0.19860973187686193","last_synced_commit":"a4b5190ee32b9093a027d41c62d0801a1277e923"},"previous_names":["matchtechnologies/fitting"],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuwilof%2Ffitting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuwilof%2Ffitting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuwilof%2Ffitting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuwilof%2Ffitting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuwilof","download_url":"https://codeload.github.com/tuwilof/fitting/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248008630,"owners_count":21032556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-blueprint","consumer-driven-contracts","coverage","coverage-api","document-driven-development","drafter","json-schema","openapi","openapi3","rspec","swagger","tests-coverage","validation","webmock"],"created_at":"2024-08-06T08:01:59.333Z","updated_at":"2025-04-09T09:08:46.416Z","avatar_url":"https://github.com/tuwilof.png","language":"Ruby","readme":"# Fitting\n\n\u003cimg align=\"right\" width=\"192\" height=\"192\"\nalt=\"Fitting avatar: Documents with hangers\"\nsrc=\"./images/logo.png\"\u003e\n\n\n\nLibrary add improve test log, validate its according to your API documentation, show the documentation coverage with log.\n\nTest log setting supports RSpec test and WebMock stubbing for Ruby On Rails application, API documentation supports API Blueprint and OpenAPI.\n\nThis reduces the costs of support, testers and analysts.\n\n[Telegram community for any Fitting related questions](https://t.me/+NFojMTCFJ-1iNDYy)\n\nLog\n```text\nFITTING incoming request {\"method\":\"POST\",\"path\":\"/public/api/v1/inboxes/tEX5JiZyceiwuKMi1oN9Sf8S/contacts\",\"body\":{},\"response\":{\"status\":200,\"content_type\":\"application/json\",\"body\":{\"source_id\":\"00dbf18d-879e-47cb-ac45-e9aece266eb1\",\"pubsub_token\":\"ktn6YwPus57JDf4e59eFPom5\",\"id\":3291,\"name\":\"shy-surf-401\",\"email\":null,\"phone_number\":null}},\"title\":\"./spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb:9\",\"group\":\"./spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb\",\"host\":\"www.example.com\"}\nFITTING outgoing request {\"method\":\"POST\",\"path\":\"/v1/organizations/org_id/meeting\",\"body\":{},\"response\":{\"status\":200,\"content_type\":\"application/json\",\"body\":{\"success\":true,\"data\":{\"meeting\":{\"id\":\"meeting_id\",\"roomName\":\"room_name\"}}}},\"title\":\"./spec/controllers/api/v1/accounts/integrations/dyte_controller_spec.rb:50\",\"group\":\"./spec/controllers/api/v1/accounts/integrations/dyte_controller_spec.rb\",\"host\":\"api.cluster.dyte.in\"}\n```\n\nvalidation\n```console\nFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.FFF..FFFFFFFFFF....F.......F...FF.....F...F....F..............................FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF..FF.F..FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF..FF........FFF...FFFF......FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF........FFFFFFFFFFF..FFFFFF..FFFFFFFFFFFFFFFFF.......FFFFFF.............FFFFFFFFFFFF....F........FFF.F...FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF............FF........FFF......FFFFFFFFFFFFFFFFFFFFFF....FFFFFF......F............FFFF........FFFFFFFFFFFFFF.....FFFFFFFFFFFFFFFFFFFFFFF..FF.....FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.....FF..........FFFFFFFFFFFFFFFFFF...FFFF...............F.F....FF..FFFFFFFF\n\n  1) Fitting::Doc::NotFound log error:\n\nhost: www.example.com\nmethod: POST\npath: /public/api/v1/inboxes/{inbox_identifier}/contacts\ncode: 200\n\ncontent-type: application/json\n\njson-schema: {\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"id\": {\n      \"type\": \"integer\",\n      \"description\": \"Id of the contact\"\n    },\n    \"source_id\": {\n      \"type\": \"string\",\n      \"description\": \"The session identifier of the contact\"\n    },\n    \"name\": {\n      \"type\": \"string\",\n      \"description\": \"Name of the contact\"\n    },\n    \"email\": {\n      \"type\": \"string\",\n      \"description\": \"Email of the contact\"\n    },\n    \"pubsub_token\": {\n      \"type\": \"string\",\n      \"description\": \"The token to be used to connect to chatwoot websocket\"\n    }\n  }\n}\n\nbody: {\n  \"source_id\": \"c9e8c31f-06df-49b4-8fb9-4466457ae65b\",\n  \"pubsub_token\": \"Zgc7DEvaj5TkgZ1a4C7AvJXo\",\n  \"id\": 3293,\n  \"name\": \"restless-snowflake-670\",\n  \"email\": null,\n  \"phone_number\": null\n}\n\nerror [\n  \"The property '#/email' of type null did not match the following type: string in schema e56b7e65-d70c-5f7a-a96c-982df5f8f2f7\"\n]\n\n...\n\n804 examples, 565 failure, 0 pending\n\nCoverage: 65.51%\n```\n\nand cover\n![exmaple](images/b1.png)\n\n![exmaple](images/b2.png)\n\n![exmaple](images/w1.png)\n\n![exmaple](images/w2.png)\n\n## Installation\nAdd this line to your application's Gemfile:\n```ruby\ngem 'fitting'\n```\n\nAfter that execute:\n```bash\n$ bundle\n```\n\nOr install the gem by yourself:\n```bash\n$ gem install fitting\n```\n\n## Usage\n### Log\nFirstly, improve `test.log`.\n\nTo your `spec_helper.rb`:\n\n```ruby\nrequire 'fitting'\n\nFitting.logger\n```\n\nDelete all files `log/*.log` and run rspec\n\nYou get more information about incoming and outgoing request in `log/fitting*.log`.\n\n```text\nFITTING incoming request {\"method\":\"POST\",\"path\":\"/public/api/v1/inboxes/tEX5JiZyceiwuKMi1oN9Sf8S/contacts\",\"body\":{},\"response\":{\"status\":200,\"content_type\":\"application/json\",\"body\":{\"source_id\":\"00dbf18d-879e-47cb-ac45-e9aece266eb1\",\"pubsub_token\":\"ktn6YwPus57JDf4e59eFPom5\",\"id\":3291,\"name\":\"shy-surf-401\",\"email\":null,\"phone_number\":null}},\"title\":\"./spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb:9\",\"group\":\"./spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb\",\"host\":\"www.example.com\"}\nFITTING outgoing request {\"method\":\"POST\",\"path\":\"/v1/organizations/org_id/meeting\",\"body\":{},\"response\":{\"status\":200,\"content_type\":\"application/json\",\"body\":{\"success\":true,\"data\":{\"meeting\":{\"id\":\"meeting_id\",\"roomName\":\"room_name\"}}}},\"title\":\"./spec/controllers/api/v1/accounts/integrations/dyte_controller_spec.rb:50\",\"group\":\"./spec/controllers/api/v1/accounts/integrations/dyte_controller_spec.rb\",\"host\":\"api.cluster.dyte.in\"}\n```\n\n### Validation\nSecondly, validate the log to the documentation.\n\nAdd this to your `.fitting.yml`:\n\n```yaml\nAPIs:\n  - host: www.example.com\n    type: openapi2\n    path: swagger/swagger.json\n```\n\nRun \n```bash\nbundle e rake fitting:validate\n```\n\nConsole output\n\n```console\nFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.FFF..FFFFFFFFFF....F.......F...FF.....F...F....F..............................FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF..FF.F..FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF..FF........FFF...FFFF......FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF........FFFFFFFFFFF..FFFFFF..FFFFFFFFFFFFFFFFF.......FFFFFF.............FFFFFFFFFFFF....F........FFF.F...FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF............FF........FFF......FFFFFFFFFFFFFFFFFFFFFF....FFFFFF......F............FFFF........FFFFFFFFFFFFFF.....FFFFFFFFFFFFFFFFFFFFFFF..FF.....FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.....FF..........FFFFFFFFFFFFFFFFFF...FFFF...............F.F....FF..FFFFFFFF\n\n  1) Fitting::Doc::NotFound log error:\n\nhost: www.example.com\nmethod: POST\npath: /public/api/v1/inboxes/{inbox_identifier}/contacts\ncode: 200\n\ncontent-type: application/json\n\njson-schema: {\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"id\": {\n      \"type\": \"integer\",\n      \"description\": \"Id of the contact\"\n    },\n    \"source_id\": {\n      \"type\": \"string\",\n      \"description\": \"The session identifier of the contact\"\n    },\n    \"name\": {\n      \"type\": \"string\",\n      \"description\": \"Name of the contact\"\n    },\n    \"email\": {\n      \"type\": \"string\",\n      \"description\": \"Email of the contact\"\n    },\n    \"pubsub_token\": {\n      \"type\": \"string\",\n      \"description\": \"The token to be used to connect to chatwoot websocket\"\n    }\n  }\n}\n\nbody: {\n  \"source_id\": \"c9e8c31f-06df-49b4-8fb9-4466457ae65b\",\n  \"pubsub_token\": \"Zgc7DEvaj5TkgZ1a4C7AvJXo\",\n  \"id\": 3293,\n  \"name\": \"restless-snowflake-670\",\n  \"email\": null,\n  \"phone_number\": null\n}\n\nerror [\n  \"The property '#/email' of type null did not match the following type: string in schema e56b7e65-d70c-5f7a-a96c-982df5f8f2f7\"\n]\n\n...\n\n804 examples, 565 failure, 0 pending\n\nCoverage: 65.51%\n```\n\n### Coverage\nAnd task will create HTML (`coverage/fitting.html`) reports.\n\n![exmaple](images/b1.png)\n\n![exmaple](images/b2.png)\n\nMore information on action coverage\n\n![exmaple2](images/w1.png)\n\n![exmaple2](images/w2.png)\n\n## Settings\n\n### APIs\n\n#### type\n\n##### OpenAPI 2.0\nSwagger\n\n```yaml\nAPIs:\n  - host: www.example.com\n    type: openapi2\n    path: doc/api.json\n```\n\n##### OpenAPI 3.0\nAlso OpenAPI\n\n```yaml\nAPIs:\n  - host: www.example.com\n    type: openapi3\n    path: doc/api.json\n```\n\n##### API Blueprint\nFirst you need to install [drafter](https://github.com/apiaryio/drafter) or [crafter](https://github.com/funbox/crafter).\nWorks after conversion from API Blueprint to API Elements (in YAML file) with Drafter or Crafter.\n\nThat is, I mean that you first need to do this\n\n```bash\ndrafter doc.apib -o doc.yaml\n```\n\nor\n\n```bash\nnode_modules/.bin/crafter doc.apib \u003e doc.yaml\n```\n\nand then\n\n```yaml\nAPIs:\n  - host: www.example.com\n    type: drafter\n    path: doc/api.yaml\n```\n\nor\n\n```yaml\nAPIs:\n  - host: www.example.com\n    type: crafter\n    path: doc/api.yaml\n```\n\n##### Tomograph\n\nTo use additional features of the pre-converted [tomograph](https://github.com/tuwilof/tomograph)\n\nexample\n\n```bash\nbundle exec tomograph -d crafter --exclude-description doc/api.yml doc/api.json\n```\n\nand then\n\n```yaml\nAPIs:\n  - host: www.example.com\n    type: tomogram\n    path: doc/api.json\n```\n\n#### prefix\n\nSetting the prefix name is optional. For example, you can do this:\n\n```yaml\nAPIs:\n  - host: www.example.com\n    prefix: /api/v3\n    type: openapi2\n    path: swagger/swagger.json\n```\n\n### SkipValidation\n\n#### host\n\nIt is not necessary to immediately describe each host in detail, you can only specify its name and skip it until you are ready to documented it\n\n```yaml\nSkipValidation:\n  - host: api.cluster.dyte.in\n```\n\n#### prefix\n\nIf you want to skip a specific prefix in the host\n\n```yaml\nSkipValidation:\n  - host: api.cluster.dyte.in\n    prefix: /admin/api\n```\n\n#### method and path\n\nIf you want to skip a specific request in the host\n\n```yaml\nSkipValidation:\n  - host: api.cluster.dyte.in\n    method: GET\n    path: /api/v1/cars\n```\n\n### NoCov\n\nIt is not necessary to immediately test each doc in detail, you can only specify its name and skip it until you are ready to test it\n\n#### host\n```yaml\nNoCov:\n  - host: sso.test\n```\n\n#### method\n```yaml\nNoCov:\n  - host: sso.test\n    method: GET\n```\n\n#### path\n```yaml\nNoCov:\n  - host: sso.test\n    method: GET\n    path: /users/{userId}\n```\n\n#### code\n```yaml\nNoCov:\n  - host: sso.test\n    method: GET\n    path: /users/{userId}\n    code: 200\n```\n\n#### content-type\n```yaml\nNoCov:\n  - host: sso.test\n    method: GET\n    path: /users/{userId}\n    code: 200\n    content-type: application/json\n```\n\n#### combination\n```yaml\nNoCov:\n  - host: sso.test\n    method: GET\n    path: /users/{userId}\n    code: 200\n    content-type: application/json\n    combination: oneOf.0\n```\n\n#### combination_next\n```yaml\nNoCov:\n  - host: sso.test\n    method: GET\n    path: /users/{userId}\n    code: 200\n    content-type: application/json\n    combination: oneOf.0\n    combination_next: oneOf.0.required.users\n```\n\n### Debug\n\nIf you find bug, you can debug it or create task in this github project  with new file `coverage/fitting.debug.yml`\n\n```yaml\nDebug:\n  - host: www.example.com\n    method: GET\n    path: /api/v3/users\n    code: 200\n    content-type: application/json\n```\n\n## Community\n\nJoin us on [Telegram](https://t.me/+NFojMTCFJ-1iNDYy).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at [github.com/tuwilof/fitting](https://github.com/tuwilof/fitting).\nThis project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n[Sponsored by FunBox](https://funbox.ru)\n","funding_links":[],"categories":["Ruby","Documentation"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuwilof%2Ffitting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuwilof%2Ffitting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuwilof%2Ffitting/lists"}