# NAME Spek # SYNOPSIS Test centric web framework # INSTALL cpanm Spek # USAGE ## declare http endpoints To declare http endpoint you should write swat tests: ### GET /users To get users list ... $ mkdir users $ touch users/get.txt ### POST /user To create a new user ... $ mkdir -p user $ touch user/post.txt ### GET /user To get user info ... $ mkdir -p user/id $ touch user/id/get.txt Follow [swat](https://github.com/melezhik/swat) for full explanation of swat test harness. ## run spek application $ spek ... you should see: HTTP::Server::PSGI: Accepting connections at http://0:5000/ ## run swat tests # in parallel console $ echo 127.0.0.1:5000 > host $ swat ... you should get an errors like ... as endpoints are not *defined* yet 127.0.0.1 - - [16/Mar/2016:09:00:03 +0300] "GET /users HTTP/1.1" 404 20 "-" "curl/7.47.0-DEV" 127.0.0.1 - - [16/Mar/2016:09:00:03 +0300] "GET /user/foo HTTP/1.1" 404 20 "-" "curl/7.47.0-DEV" 127.0.0.1 - - [16/Mar/2016:09:00:03 +0300] "POST /user HTTP/1.1" 404 20 "-" "curl/7.47.0-DEV" ## implement endpoints ### initialize application app.pm : our $USERS = { 'alex' => { 'age' => 39, 'email' => 'melezhik@gmail.com' }, 'bot' => { 'age' => 1000, 'email' => 'iamarobot@...' }, }; ### populate controllers It should be [Kelp](https://metacpan.org/pod/Kelp) routes: #### GET users/ users/get.pm : my ( $self ) = @_; my $list; for my $id ( sort keys %$USERS ) { $list.="$id: $USERS->{$id}->{email}\n"; } $list; #### GET user/id user/id/get.pm : my ($self, $id ) = @_; "id: $id email: ".($USERS->{$id}->{email}); #### POST user user/post.pm my ( $self ) = @_; $USERS->{$self->param('name')} = { email => $self->param('email'), age => $self->param('age'), }; "user ".($self->param('name'))." created OK" ## refine your tests ### Tests should be swat modules: $ echo swat_module=1 > users/swat.ini $ echo swat_module=1 > user/id/swat.ini $ echo swat_module=1 > user/swat.ini ### Some tests should pass http request parameters: #### POST /user $ echo 'curl_params="-d name=foo -d age=30 -d email='foo@bar'"' >> user/swat.ini ### Define expected response: #### POST /user : $ echo 'user foo created OK' > user/post.txt #### GET /users : $ cat users/get.txt alex: melezhik@gmail.com bot: iamarobot@... foo: foo@bar #### GET /user/id $ cat user/id/get.txt id: foo email: foo@bar ## And finally create a meta story: $ mkdir crud $ cat crud/meta.txt application should be able to perform CRUD operations $ cat crud/hook.pm run_swat_module( POST => '/user' ); run_swat_module( GET => '/user/id', { id => 'foo' } ); run_swat_module( GET => '/users' ); ## Rebuild spek app In console running spek app: $ + $ spek ... should see: reiniting spek app ... populate app.pm ... populate post /home/vagrant/my/spek-example-app/user ... populate get /home/vagrant/my/spek-example-app/user/id ... populate get /home/vagrant/my/spek-example-app/users ... HTTP::Server::PSGI: Accepting connections at http://0:5000/ ## Run tests Now you have a specifi(K)ation simply just running: $ swat ... should see: /home/vagrant/.swat/.cache/5738/prove/crud/META/request.t .. # @META # application should be able # to perform CRUD operations # ok 1 - 200 / 1 of 2 curl -X POST -k --connect-timeout 20 -m 20 -d name=foo -d age=30 -d email='foo@bar' -L -D - '127.0.0.1:5000/user' ok 2 - output match 'user foo created OK' ok 3 - 200 / 1 of 2 curl -X GET -k --connect-timeout 20 -m 20 -L -D - '127.0.0.1:5000/user/foo' ok 4 - output match 'id: foo email: foo@bar' ok 5 - 200 / 1 of 2 curl -X GET -k --connect-timeout 20 -m 20 -L -D - '127.0.0.1:5000/users' ok 6 - output match 'alex: melezhik@gmail.com' ok 7 - output match 'bot: iamarobot@...' ok 8 - output match 'foo: foo@bar' 1..8 ok All tests successful. Files=1, Tests=8, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.06 cusr 0.00 csys = 0.08 CPU) Result: PASS # Application introspection ## routes To inspect all available routes: $ spek --routes ## meta stories To inspect meta stories: $ spek --meta Read [swat](https://github.com/melezhik/swat#meta-stories) documentation to know more about swat meta stories. # Advanced usage ## handling json responses Modify Kelp controller ### GET /user/id $ cat user/id/get.pm my ($self, $id ) = @_; { id => $id, email => $USERS->{$id}->{email} , age => $USERS->{$id}->{age} } Add json handler to swat test: $ cat user/id/get.handler my $headers = shift; my $body = shift; use JSON; $hash = decode_json($body); return "$headers\n".("id: $hash->{id}\nemail: $hash->{email}\nage: $hash->{age}"); Regenerate spek application $ + # to stop running application $ spek ... should see: reiniting spek app ... populate app.pm ... populate post /home/vagrant/my/spek-example-app/user ... populate delete /home/vagrant/my/spek-example-app/user/id ... populate get /home/vagrant/my/spek-example-app/user/id ... populate get /home/vagrant/my/spek-example-app/users ... generate hook for /user/id ... inject response handler for get ... Run swat tests $ swat ... should see: ok 1 - 200 / 1 of 1 curl -X DELETE -k --connect-timeout 20 -m 20 -L -D - '127.0.0.1:5000/user/foo' # modified response saved to /home/vagrant/.swat/.cache/23224/prove/mFRKPZV6Im ok 2 - output match 'id: foo' ok 3 - output match 'message: user deleted OK' ok 4 - output match 'status: OK' Read more [swat docs](https://github.com/melezhik/swat#process-http-responses) on how to process http responses. To add handlers for other http methods simple create a proper handler file: $ DELETE /user/id $ nano user/id/delete.handler # and so on ... # Author [Alexey Melezhik](mailto:melezhik@gmail.com) # Download example spek application You can upload source code here - [https://github.com/melezhik/spek-example-app](https://github.com/melezhik/spek-example-app) # See also * [Kelp](https://metacpan.org/pod/Kelp) * [swat](https://metacpan.org/pod/swat)