1(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{400:function(t,e,s){t.exports=s.p+"assets/img/TestBoundaries.994d4c20.svg"},412:function(t,e,s){"use strict";s.r(e);var a=s(56),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing-programs-with-interactive-html"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing-programs-with-interactive-html"}},[t._v("#")]),t._v(" Testing programs with interactive HTML")]),t._v(" "),a("p",[a("a",{attrs:{href:"https://package.elm-lang.org/packages/elm-explorations/test/latest/Test-Html-Query",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Test.Html")]),t._v(" from the "),a("code",[t._v("elm-explorations/test")]),t._v(" package"),a("OutboundLink")],1),t._v("\nmake it possible to write unit tests for functions that return "),a("code",[t._v("Html msg")]),t._v(",\nbut often\n(especially when your view is complicated enough to need to be tested)\ngood test coverage requires testing the interactions between your "),a("code",[t._v("view")]),t._v(" and your "),a("code",[t._v("update")]),t._v(" functions\n(w
1hich communicate via the "),a("code",[t._v("Model")]),t._v(" and "),a("code",[t._v("Msg")]),t._v("s, as explained in "),a("a",{attrs:{href:"https://guide.elm-lang.org/architecture/",target:"_blank",rel:"noopener noreferrer"}},[t._v('"An Introduction to Elm: The Elm Architecture"'),a("OutboundLink")],1),t._v(").")]),t._v(" "),a("p",[a("code",[t._v("elm-program-test")]),t._v(' lets you write "high-level" tests for your program,\ntesting the public interface of your program rather than\ntesting '),a("code",[t._v("view")]),t._v(" and "),a("code",[t._v("update")]),t._v(" functions independently.\nThis gives you the flexibility to test complex interactions\nbetween your "),a("code",[t._v("view")]),t._v(", "),a("code",[t._v("update")]),t._v(", and the state of your program\nin a way that's extremely resiliant to refactoring;\nand allows you to write your tests in terms of\nhow users and external services interact with your program.")]),t._v(" "),a("p",[a("img",{attrs:{src:s(400),alt:"diagram of testing boundaries described in the preceding paragraph"}})]),t._v(" "),a("h2",{attrs:{id:"introducing-the-example-program"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#introducing-the-example-program"}},[t._v("#")]),t._v(" Introducing the example program")]),t._v(" "),a("p",[t._v("In this example, we'll be working with simple voter registration form.\nHere's the page flow a user will experience:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("+----------------+ +---------------+\n| | | |\n| | | |\n| Name: | +------------+ | Success! |\n| | | | | |\n| Street | submit | | | |\n| Address: |---------\x3e| Loading... |-------\x3e| Next election |\n| | | | | date is ... |\n| Postal code: | | | | |\n| | +------------+ | |\n| | | |\n| | | |\n+----------------+ +---------------+\n")])])]),a("p",[t._v('We\'ll be using elm-program-test to help us add field validation for the\n"Postal code" field.')]),t._v(" "),a("p",[t._v("Using "),a("code",[t._v("elm-program-test")]),t._v(" will also\nhelp us build our UI in a way that makes it follow\nsome accessibility best practices.")]),t._v(" "),a("h2",{attrs:{id:"writing-a-program-test"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#writing-a-program-test"}},[t._v("#")]),t._v(" Writing a program test")]),t._v(" "),a("p",[t._v("Our goal will be to write a test for the following scenario:")]),t._v(" "),a("ul",[a("li",[t._v("The user fills in the form with:\n"),a("ul",[a("li",[t._v("their name")]),t._v(" "),a("li",[t._v("their street address")]),t._v(" "),a("li",[t._v("an "),a("strong",[t._v("invalid postal code")])])])]),t._v(" "),a("li",[t._v("The user tries to submit the form")]),t._v(" "),a("li",[t._v("The app should show a validation error")])]),t._v(" "),a("h3",{attrs:{id:"preparing-to-write-a-program-test"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#preparing-to-write-a-program-test"}},[t._v("#")]),t._v(" Preparing to write a program test")]),t._v(" "),a("p",[t._v("Before we can write our actual test, we need to define how to create tests for our program.\nThis is similar to writing the "),a("code",[t._v("main")]),t._v(" definition for using your app in production.\nIt's typical to call this definition "),a("code",[t._v("start")]),t._v(" in your test file, but it can be called anything.")]),t._v(" "),a("p",[t._v("Here's the "),a("code",[t._v("start")]),t._v(" definition for our example program:")]),t._v(" "),a("div",{staticClass:"language-elm extra-class"},[a("pre",{pre:!0,attrs:{class:"language-elm"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("module")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("VoterRegistrationExampleTest")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("exposing")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token import-statement"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" ProgramTest "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("exposing")]),t._v(" ")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}}
1,[t._v("ProgramTest")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token import-statement"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" VoterRegistrationExample "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Main")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("start")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("ProgramTest")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Main.Model")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Main.Msg")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Cmd")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Main.Msg")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("start")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("ProgramTest.createDocument")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("init")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("Main.init")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("update")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("Main.update")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("view")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("Main.view")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|>
1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("ProgramTest.start")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("Just like when using one of the "),a("code",[t._v("Browser")]),t._v(" module functions to create your real program,\nhere we use one of the "),a("code",[t._v("ProgramTest.create*")]),t._v(" functions to create our program test.\nWe provide the "),a("code",[t._v("init")]),t._v(", "),a("code",[t._v("update")]),t._v(", and "),a("code",[t._v("view")]),t._v(" functions that comprise our program.\nAfter creating the program test definition, we use "),a("code",[t._v("ProgramTest.start")]),t._v(" to pass the initial\nflags to the program.")]),t._v(" "),a("h3",{attrs:{id:"writing-our-test"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#writing-our-test"}},[t._v("#")]),t._v(" Writing our test")]),t._v(" "),a("p",[t._v("Now that we've defined how to start our program, we can write our test:")]),t._v(" "),a("div",{staticClass:"language-elm extra-class"},[a("pre",{pre:!0,attrs:{class:"language-elm"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("module")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("VoterRegistrationExampleTest")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("exposing")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token import-statement"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" ProgramTest "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("exposing")]),t._v(" ")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("ProgramTest")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("clickButton")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("expectViewHas")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("fillIn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("update")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token import-statement"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Test "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("exposing")]),t._v(" ")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token import-statement"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Test.Html.Selector "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("exposing")]),t._v(" ")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("text")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token import-statement"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" VoterRegistrationExample "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Main")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("all")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Test")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("all")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("describe")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"voter registration frontend"')]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("test")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"invalid postal code shows a validation error"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<|")]),t._v("\n \\"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("start")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|>
1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("fillIn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Name"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Bailey Sheppard"')]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("fillIn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"street-address"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Street Address"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"14 North Moore Street"')]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("fillIn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"postcode"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Postal Code"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0000"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("-- (only 4 digits)")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|>
1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("clickButton")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Register"')]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("expectViewHas")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token hvariable"}},[t._v("text")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"You must enter a valid postal code"')]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("Here we use "),a("code",[t._v("start")]),t._v(" (which we defined in the previous section) to initialize the program,\nthen simulate some user input using "),a("code",[t._v("fillIn")]),t._v(" and "),a("code",[t._v("clickButton")]),t._v(",\nand finally we assert something about the final state of the page.")]),t._v(" "),a("p",[t._v("Running the test gives us the following error:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v('â VoterRegistrationExampleTest\nâ voter registration frontend\nâ invalid postal code shows a validation error\n\n expectViewHas:\n â¼ Query.fromHtml\n \n <body>\n Loading...\n </body>\n\n \n â¼ Query.has [ text "You must enter a valid postal code" ]\n \n â has text "You must enter a valid postal code"\n\n\nTEST RUN FAILED\n')])])]),a("h3",{attrs:{id:"implementing-the-change"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#implementing-the-change"}},[t._v("#")]),t._v(" Implementing the change")]),t._v(" "),a("p",[t._v("This section doesn't explain anything specific to elm-program-test, but for completeness\nhere are the changes needed to make the test pass:")]),t._v(" "),a("div",{staticClass:"language-diff extra-class"},[a("pre",{pre:!0,attrs:{class:"language-diff"}},[a("code",[a("span",{pre:!0,attrs:{class:"token coord"}},[t._v("--- a/src/VoterRegistrationExample.elm")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token coord"}},[t._v("+++ b/src/VoterRegistrationExample.elm")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("type Model\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" = Form\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" { name : String\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , streetAddress : String\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , postalCode : String\n")])]),a("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , error : Maybe String\n")])]),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" }\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" | ...\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("init : Flags -> ( Model, Cmd Msg )\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("init () =\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ( Form\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' { name = ""\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' , streetAddress = ""\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' , postalCode = ""\n')])]),a("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , error = Nothing\n")])]),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" }\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , Cmd.none\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" )\n")])]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("update msg model =\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" case ( model, msg) of\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ...\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ( Form info, SubmitRegistration ) ->\n")])]),a("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" let\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" isValid =\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" String.length info.postalCode == 5\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" in\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" if isValid then\n")])]),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ( Loading\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , Http.post\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' { url = "/register"\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , body =\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" Http.jsonBody <|\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" Json.Encode.object\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' [ ( "name", Json.Encode.string info.name )\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' , ( "streetAddress", Json.Encode.string info.streetAddress )\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' , ( "postalCode", Json.Encode.string info.postalCode )\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ]\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , expect =\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" Http.expectJson\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" RegistrationResponse\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' (Json.Decode.field "nextElection" Json.Decode.string)\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" }\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" )\n")])]),a("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" else\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' ( Form { info | error = Just "You must enter a valid postal code" }\n')]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , Cmd.none\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" )\n")])]),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ...\n")])]),t._v("\n\nview : Model -> Browser.Document Msg\n"),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ...\n")])]),a("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , case info.error of\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" Nothing ->\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' Html.text ""\n')]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v("\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" Just error ->\n")]),a("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" Html.text error\n")])]),a("span",{pre:!0,attrs:{class:"token unchanged"}},[a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" , Html.button\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" [ onClick SubmitRegistration ]\n")]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(' [ Html.text "Register" ]\n')]),a("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token line"}},[t._v(" ...\n")])])])])]),a("h2",{attrs:{id:"try-it-out"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#try-it-out"}},[t._v("#")]),t._v(" Try it out")]),t._v(" "),a("p",[t._v("You can play around with the example here:\n"),a("a",{attrs:{href:"https://ellie-app.com/6wsc2LK2D97a1",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://ellie-app.com/6wsc2LK2D97a1"),a("OutboundLink")],1),t._v("\nTry editing the tests or the implementation to make the tests fail\nand see what kind of failure messages you get.")])])}),[],!1,null,null,null);e.default=n.exports}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.