{"id":13483884,"url":"https://github.com/c910335/mass-spec","last_synced_at":"2025-03-27T15:30:37.157Z","repository":{"id":54732872,"uuid":"130995430","full_name":"c910335/mass-spec","owner":"c910335","description":"Web API testing library","archived":false,"fork":false,"pushed_at":"2023-06-21T12:03:40.000Z","size":41,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-30T17:48:19.992Z","etag":null,"topics":["crystal","testing"],"latest_commit_sha":null,"homepage":"","language":"Crystal","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/c910335.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-04-25T11:21:01.000Z","updated_at":"2022-11-07T11:05:18.000Z","dependencies_parsed_at":"2022-08-14T01:10:25.629Z","dependency_job_id":"f6c062d7-2374-46ee-b1ae-55089c107ef5","html_url":"https://github.com/c910335/mass-spec","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c910335%2Fmass-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c910335%2Fmass-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c910335%2Fmass-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c910335%2Fmass-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c910335","download_url":"https://codeload.github.com/c910335/mass-spec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245871683,"owners_count":20686246,"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":["crystal","testing"],"created_at":"2024-07-31T17:01:16.466Z","updated_at":"2025-03-27T15:30:36.764Z","avatar_url":"https://github.com/c910335.png","language":"Crystal","funding_links":[],"categories":["Testing"],"sub_categories":[],"readme":"# Mass Spec\n\n[![Crystal CI](https://github.com/c910335/mass-spec/actions/workflows/crystal.yml/badge.svg)](https://github.com/c910335/mass-spec/actions/workflows/crystal.yml)\n[![GitHub releases](https://img.shields.io/github/release/c910335/mass-spec.svg)](https://github.com/c910335/mass-spec/releases)\n[![GitHub license](https://img.shields.io/github/license/c910335/mass-spec.svg)](https://github.com/c910335/mass-spec/blob/master/LICENSE)\n\nWeb API testing library\n\nMass Spec prevents [`HTTP::Server`](https://crystal-lang.org/api/latest/HTTP/Server.html) from starting a [`TCPServer`](https://crystal-lang.org/api/latest/TCPServer.html) and use [`IO::Memory`](https://crystal-lang.org/api/latest/IO/Memory.html) instead of [`TCPSocket`](https://crystal-lang.org/api/latest/TCPSocket.html) for fast testing.\n\nSince Mass Spec works with standard library, it can easily support the frameworks based on [`HTTP::Server`](https://crystal-lang.org/api/latest/HTTP/Server.html).\n\n## Installation\n\nAdd this to your application's `shard.yml`:\n\n```yaml\ndevelopment_dependencies:\n  mass_spec:\n    github: c910335/mass-spec\n```\n\n## Usage\n\n```crystal\nrequire \"spec\"\nrequire \"mass_spec\"\ninclude MassSpec::GlobalDSL\n\nserver = HTTP::Server.new do |context|\n  context.response.content_type = \"application/json\"\n  context.response.print(context.request.body.try \u0026.gets_to_end)\nend\n\nserver.listen\n\ndescribe \"Server\" do\n  it \"echoes in json\" do\n    post(\"/\", body: {\n      \"Khassar de templari!\" =\u003e \"From order comes justice!\",\n      \"Adun Toridas!\"        =\u003e \"Adun hide you\",\n      \"Nahda gahla\"          =\u003e nil,\n    }.to_json)\n\n    status_code.should eq(200)\n    headers.should contain({\"Content-Type\", [\"application/json\"]})\n    body.should eq(%({\"Khassar de templari!\":\"From order comes justice!\",\"Adun Toridas!\":\"Adun hide you\",\"Nahda gahla\":null}))\n    json_body.should eq({\n      \"Khassar de templari!\" =\u003e \"From order comes justice!\",\n      \"Adun Toridas!\"        =\u003e \"Adun hide you\",\n      \"Nahda gahla\"          =\u003e nil,\n    })\n\n    json_body.should contain({\n      \"Khassar de templari!\" =\u003e \"From order comes justice!\",\n      \"Adun Toridas!\"        =\u003e String,\n    })\n    json_body.should match({\n      \"Khassar de templari!\" =\u003e String,\n      \"Adun Toridas!\"        =\u003e \"Adun hide you\",\n      \"Nahda gahla\"          =\u003e Nil,\n    })\n  end\nend\n```\n\n### Making Requests\n\nMass Spec supports the following HTTP verbs via [`HTTP::Client`](https://crystal-lang.org/api/latest/HTTP/Client.html), and the usage of them is the same as [`HTTP::Client`](https://crystal-lang.org/api/latest/HTTP/Client.html).\n\n- [`#get`](https://crystal-lang.org/api/latest/HTTP/Client.html#get%28path%2Cheaders%3AHTTP%3A%3AHeaders%3F%3Dnil%2C%2A%2Cform%3AHash%28String%2CString%29%7CNamedTuple%29%3AHTTP%3A%3AClient%3A%3AResponse-instance-method)\n- [`#head`](https://crystal-lang.org/api/latest/HTTP/Client.html#head%28path%2Cheaders%3AHTTP%3A%3AHeaders%3F%3Dnil%2C%2A%2Cform%3AHash%28String%2CString%29%7CNamedTuple%29%3AHTTP%3A%3AClient%3A%3AResponse-instance-method)\n- [`#post`](https://crystal-lang.org/api/latest/HTTP/Client.html#post%28path%2Cheaders%3AHTTP%3A%3AHeaders%3F%3Dnil%2C%2A%2Cform%3AHash%28String%2CString%29%7CNamedTuple%29%3AHTTP%3A%3AClient%3A%3AResponse-instance-method)\n- [`#put`](https://crystal-lang.org/api/latest/HTTP/Client.html#put%28path%2Cheaders%3AHTTP%3A%3AHeaders%3F%3Dnil%2Cbody%3ABodyType%3Dnil%2C%26block%29-instance-method)\n- [`#patch`](https://crystal-lang.org/api/latest/HTTP/Client.html#patch%28path%2Cheaders%3AHTTP%3A%3AHeaders%3F%3Dnil%2C%2A%2Cform%3AHash%28String%2CString%29%7CNamedTuple%29%3AHTTP%3A%3AClient%3A%3AResponse-instance-method)\n- [`#delete`](https://crystal-lang.org/api/latest/HTTP/Client.html#delete%28path%2Cheaders%3AHTTP%3A%3AHeaders%3F%3Dnil%2Cbody%3ABodyType%3Dnil%29%3AHTTP%3A%3AClient%3A%3AResponse-instance-method)\n\n### Handling Responses\n\nAfter a request, you can access these getters.\n\n- response : [`HTTP::Client::Response`](https://crystal-lang.org/api/latest/HTTP/Client/Response.html)\n- status_code : [`Int32`](https://crystal-lang.org/api/latest/Int32.html)\n- headers : [`HTTP::Headers`](https://crystal-lang.org/api/latest/HTTP/Headers.html)\n- body : [`String`](https://crystal-lang.org/api/latest/String.html)\n- json_body : [`JSON::Any`](https://crystal-lang.org/api/latest/JSON/Any.html) - The body parsed as [`JSON::Any`](https://crystal-lang.org/api/latest/JSON/Any.html)\n\n### Expectations\n\nBesides built-in expectations, Mass Spec also provides `contain` and `match` for `JSON::Any`.\n\n```crystal\njson = JSON.parse(%({\"array\":[1,2,3],\"number\":1,\"float_number\":1.5,\"string\":\"str\",\"null\":null,\"hash\":{\"a\":1}}))\n\ndescribe \"contain with JSON::Any\" do\n  it \"checks whether json contains the values or types\" do\n    json.should contain({\n      \"array\"  =\u003e Array,\n      \"number\" =\u003e 1,\n      \"hash\"   =\u003e {\"a\" =\u003e Int64},\n    })\n  end\nend\n\ndescribe \"match with JSON::Any\" do\n  it \"checks whether json matches the values or types\" do\n    json.should match({\n      \"array\"        =\u003e [1, 2, 3],\n      \"number\"       =\u003e Int64,\n      \"float_number\" =\u003e 1.5,\n      \"string\"       =\u003e String,\n      \"null\"         =\u003e nil,\n      \"hash\"         =\u003e Hash,\n    })\n  end\nend\n```\n\n### Configuration\n\nYou can specify `headers` that will be applied to every requests.\n\n```crystal\nMassSpec.configure do\n  headers({\"Authorization\" =\u003e \"Bearer some_access_token\"})\nend\n```\n\n### Frameworks\n\n#### [Kemal](https://github.com/kemalcr/kemal)\n\nKemal doesn't run `HTTP::Server#listen` when `ENV[\"KEMAL_ENV\"]` is `\"test\"`, so you need to set `MassSpec.server` manually.\n\n```crystal\n# src/your_app.cr\nrequire \"kemal\"\n\nget \"/hello\" do\n  {hello: \"kemal\"}.to_json\nend\n\nKemal.run\n\n# spec/spec_helper.cr\nENV[\"KEMAL_ENV\"] = \"test\"\nrequire \"spec\"\nrequire \"mass_spec\"\nrequire \"../src/*\"\ninclude MassSpec::GlobalDSL\n\nKemal.run do |config|\n  MassSpec.server = config.server.not_nil! # set `MassSpec.server` manually\nend\n\n# spec/your_app_spec.cr\nrequire \"./spec_helper\"\n\ndescribe \"GET /hello\" do\n  it \"says hello to Kemal\" do\n    get \"/hello\"\n\n    json_body.should eq({\"hello\" =\u003e \"kemal\"})\n  end\nend\n```\n\n#### [Amber](https://github.com/amberframework/amber)\n\n```crystal\n# src/controllers/hello_controller.cr\nclass HelloController \u003c Amber::Controller::Base\n  def hello\n    respond_with { json({\"hello\" =\u003e \"amber\"}) }\n  end\nend\n\n# config/routes.cr\nAmber::Server.configure do\n  routes :web do\n    get \"/hello\", HelloController, :hello\n  end\nend\n\n# spec/spec_helper.cr\nENV[\"AMBER_ENV\"] = \"test\"\nrequire \"spec\"\nrequire \"mass_spec\"\nrequire \"../src/*\" # not `require \"../config/*\"`\ninclude MassSpec::GlobalDSL\n\n# spec/controllers/spec_helper.cr\nrequire \"../spec_helper\"\n\n# spec/controllers/hello_controller_spec.cr\nrequire \"./spec_helper\"\n\ndescribe HelloController do\n  describe \"GET #hello\" do\n    it \"says hello to Amber\" do\n      get \"/hello\"\n\n      json_body.should eq({\"hello\" =\u003e \"amber\"})\n    end\n  end\nend\n```\n\n## Contributing\n\n1. Fork it ( https://github.com/c910335/mass-spec/fork )\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Commit your changes (git commit -am 'Add some feature')\n4. Push to the branch (git push origin my-new-feature)\n5. Create a new Pull Request\n\n## Contributors\n\n- [c910335](https://github.com/c910335) Tatsiujin Chin - creator, maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc910335%2Fmass-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc910335%2Fmass-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc910335%2Fmass-spec/lists"}