{"action":"opened","issue":{"url":"https://api.github.com/repos/PSPDFKit-labs/bypass/issues/18","repository_url":"https://api.github.com/repos/PSPDFKit-labs/bypass","labels_url":"https://api.github.com/repos/PSPDFKit-labs/bypass/issues/18/labels{/name}","comments_url":"https://api.github.com/repos/PSPDFKit-labs/bypass/issues/18/comments","events_url":"https://api.github.com/repos/PSPDFKit-labs/bypass/issues/18/events","html_url":"https://github.com/PSPDFKit-labs/bypass/issues/18","id":158492210,"number":18,"title":"[Proposal] Support multiple expectation blocks with routing and more","user":{"login":"alco","id":207748,"avatar_url":"https://avatars.githubusercontent.com/u/207748?v=3","gravatar_id":"","url":"https://api.github.com/users/alco","html_url":"https://github.com/alco","followers_url":"https://api.github.com/users/alco/followers","following_url":"https://api.github.com/users/alco/following{/other_user}","gists_url":"https://api.github.com/users/alco/gists{/gist_id}","starred_url":"https://api.github.com/users/alco/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alco/subscriptions","organizations_url":"https://api.github.com/users/alco/orgs","repos_url":"https://api.github.com/users/alco/repos","events_url":"https://api.github.com/users/alco/events{/privacy}","received_events_url":"https://api.github.com/users/alco/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2016-06-04T07:17:48Z","updated_at":"2016-06-04T07:17:48Z","closed_at":null,"body":"## Background\r\n\r\nCurrently Bypass allows users to install a single `expect` handler that should be invoked one or more times to make the test containing it pass. The \"one or more\" semantics is not as strict as some people might expect.\r\n\r\nAdditionally, the current implementation cannot handle concurrent requests (see https://github.com/PSPDFKit-labs/bypass/issues/12). This behaviour is not intentional and it is desirable to support concurrent requests in order to accommodate for such use cases that require this. After all, testing with Bypass should not require changes to the application code and it's easy to imagine an application that has this behaviour by default.\r\n\r\nAnother limitation that has been reported is the inability to specify multiple routes on a single Bypass instance, see https://github.com/PSPDFKit-labs/bypass/issues/10. Supporting this functionality is also desirable in order to allow for testing more complex behaviours.\r\n\r\nThis proposal addresses those points by introducing several new functions.\r\n\r\n## `expect/2` and `expect/4`\r\n\r\n  * `expect(bypass_instance, fn conn -> ... end)`\r\n  * `expect(bypass_instance, <method> | [<method>, ...], <route>, fn conn -> ... end)`\r\n\r\nThe first form works exactly the same as the existing function but it will support concurrent requests.\r\n\r\nThe second form allows installing multiple handlers so long as each one has a unique method-route combination, each of which has to be invoked at least once for the test to pass.\r\n\r\n## `expect_once/2` and `expect_once/4`\r\n\r\n  * `expect_once(bypass_instance, fn conn -> ... end)`\r\n  * `expect_once(bypass_instance, <method> | [<method>, ...], <route>, fn conn -> ... end)`\r\n\r\nThe first form adds a handler that should be invoked exactly once for the test to pass.\r\n\r\nThe second form allows installing more than one handler as long as each one has a unique method-route combination. Each of the handlers has to be invoked exactly once in order for the test to pass.\r\n\r\n\r\n## Notes\r\n\r\n  * Both `expect/4` and `expect_once/4` take one or more HTTP method names as strings. Passing a\r\n    list means that requests that use any of the methods in the list will match.\r\n\r\n    The `<route>` is a list of route segments. This allows for doing things like dynamic and\r\n    wildcard segments without problem.\r\n\r\n  * All `expect/*` functions will return a handler ref. This ref will be accepted in calls to\r\n    `pass`, `down`, and `up` allowing to selectively disable or pass each individual handler. Passing\r\n    the Bypass instance to any of those functions will continue to work and will affect all\r\n    handlers belonging to that instance at once.\r\n\r\n  * As a sample use case, by using the building blocks proposed here it is possible to build a state machine out of expectations by relying on an external storage for state. Here is an example using an Agent:\r\n\r\n    ```elixir\r\n    import Bypass, except: [open: 0]\r\n    import Plug.Conn, only: [resp: 3]\r\n\r\n    test \"multi-step request\" do\r\n      agent = Agent.start_link(fn -> 1 end)\r\n      increment_fn = fn ->\r\n        Agent.get_and_update(agent, fn step_no -> {step_no, step_no+1} end)\r\n      end\r\n\r\n      bypass = Bypass.open\r\n      expect(bypass, \"GET\", [\"foo\"], fn conn ->\r\n        case increment_fn.() do\r\n          1 -> resp(conn, 404, \"\")\r\n          4 -> resp(conn, 200, \"\")\r\n          _ -> flunk \"I didn't expect that\"\r\n        end\r\n      end)\r\n      expect_once(bypass, \"GET\", [\"bar\"], fn conn ->\r\n        assert 2 == increment_fn.()\r\n        resp(conn, 200, \"\")\r\n      end)\r\n      expect_once(bypass, \"POST\", [\"foo\"], fn conn ->\r\n        assert 3 == increment_fn.()\r\n        resp(conn, 200, \"\")\r\n      end)\r\n\r\n\r\n      HTTPClient.go(bypass.port)\r\n    end\r\n    ```"}}
{"actor":{"display_login":"alco"}}