Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add seq/par and hook #83

Merged
merged 39 commits into from
Mar 20, 2019
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4e06727
add seq/par
safareli Dec 10, 2018
daf6b33
add hoist and example/tests
safareli Dec 11, 2018
ed1e0bf
restore handwritten show/eq instances
safareli Dec 11, 2018
47605c5
revert whitespace
safareli Dec 11, 2018
37e278b
add docs for parallel
safareli Jan 8, 2019
0681a83
src compiles
safareli Jan 10, 2019
114f8bb
add hoist and some cleanup
safareli Jan 10, 2019
2ad5c0c
moved Aff tests into Predicates
safareli Jan 11, 2019
b356736
add Path to Runner.Events
safareli Jan 11, 2019
12168c8
adopt ConsoleReporter to parallel execution
safareli Jan 14, 2019
ec4bda6
some cleanup
safareli Jan 14, 2019
1232a9a
update reporter with copy&paste
safareli Jan 14, 2019
1459670
put Speed and Duration in Success
safareli Jan 14, 2019
e1df5dd
merge Fail and Pass into TestEnd
safareli Jan 14, 2019
f433b4d
optimize redraw
safareli Jan 14, 2019
8ae1a00
use Ansi codes for screan clearing
safareli Jan 14, 2019
58d4f9e
optimize redraw
safareli Jan 15, 2019
d22706f
no redraw
safareli Jan 15, 2019
6baa794
refactor styling
safareli Jan 15, 2019
d6bcba2
restore log in hoistSpec test
safareli Jan 15, 2019
51d385a
use List instead of Array
safareli Jan 15, 2019
66b67e6
move indent to Style
safareli Jan 15, 2019
94a08ec
remove defaultUpdate
safareli Jan 15, 2019
f6746aa
refactor common parts from Console and Spec into defaultUpdate
safareli Jan 15, 2019
395b4b2
extract parallelSpec
safareli Jan 15, 2019
3d71414
comment failing tests
safareli Jan 15, 2019
30d68f6
adopt `Using hooks` section from hspec
safareli Jan 16, 2019
00f8589
use purescripts-now and Milliseconds instead of Int
safareli Jan 16, 2019
239491b
update Reporter exports
safareli Jan 16, 2019
4bf23d7
use absurd for handling void case
safareli Jan 16, 2019
2884c0c
remove reduce run,run',runSpec,runSpec' to just runSpec and runSpecM
safareli Jan 16, 2019
21f2a98
remove extra ()
safareli Jan 16, 2019
4cbccc2
fix warning
safareli Jan 16, 2019
14f5edc
use newtype instead of type alias to get better type derivation
safareli Jan 16, 2019
708bc0e
some documentation updates
safareli Jan 16, 2019
375b9d7
restore run with warning
safareli Feb 7, 2019
c3780f0
add collect
safareli Feb 7, 2019
0d50c9c
allow chaning of `m` in hoistSpec and mapSpecTree
safareli Feb 7, 2019
85c503f
fix warning
safareli Feb 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# editorconfig.org

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
5 changes: 4 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"url": "git://github.com/purescript-spec/purescript-spec.git"
},
"dependencies": {
"purescript-avar": "^3.0.0",
"purescript-console": "^4.1.0",
"purescript-aff": "^5.0.0",
"purescript-exceptions": "^4.0.0",
Expand All @@ -24,6 +25,8 @@
"purescript-foldable-traversable": "^4.0.0",
"purescript-pipes": "^6.0.0",
"purescript-ansi": "^5.0.0",
"purescript-generics-rep": "^6.0.0"
"purescript-generics-rep": "^6.0.0",
"purescript-fork": "^4.0.0",
"purescript-now": "^4.0.0"
}
}
17 changes: 9 additions & 8 deletions docs/running.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# Running

When you have a spec, you need a runner to actually run it and get the results.
PureScript Spec comes with a NodeJS runner, `run`, which takes an array of
PureScript Spec comes with a NodeJS runner, `runSpec`, which takes an array of
*reporters* and a spec to run. What you get back is a test-running program of
type `Effect ()`. The effect rows in `r` depend on what you do in your specs and
what reporters you are using. The program can be run using
type `Aff Unit`. The program can be run using
[Pulp](https://github.com/bodil/pulp).

```bash
Expand All @@ -25,13 +24,13 @@ After that has finished, you can run the test program using NodeJS.
NODE_PATH=output node -e "require('Test.Main').main();"
```

**NOTE:** A test program using `Test.Spec.Runner.run` cannot be browserified
**NOTE:** A test program using `Test.Spec.Runner.runSpec` cannot be browserified
and run in the browser, it requires NodeJS. To run your tests in a browser,
see [Browser Testing](#browser-testing) below.

## Reporters

Reporters can be passed to the runner, e.g. `run [reporter1, ..., reporterN]
Reporters can be passed to the runner, e.g. `runSpec [reporter1, ..., reporterN]
spec`. Currently there are these reporters available:

* `consoleReporter` in `Test.Spec.Reporter.Console`
Expand All @@ -42,11 +41,13 @@ spec`. Currently there are these reporters available:

## Passing Runner Configuration

In addition to the regular `run` function, there is also `run'`, which takes a
`Config` record.
In addition to the regular `runSpec` function, there is also `runSpecT`, which also
takes `Config` record. also instead of `Spec Unit` it takes `SpecT Aff Unit m Unit`
and returns `m (Aff (Array (Tree Void Result)))`. if we specialize the `m` to `Identity`
then code will look like this:

```purescript
main = launchAff_ $ run' testConfig [consoleReporter] mySpec
main = launchAff_ $ un Identity $ runSpecT testConfig [consoleReporter] mySpec
where
testConfig = { slow: 5000, timeout: Just 10000, exit: false }
```
Expand Down
196 changes: 192 additions & 4 deletions docs/writing-specs.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ import Effect.Aff (launchAff_, delay)
import Test.Spec (pending, describe, it)
import Test.Spec.Assertions (shouldEqual)
import Test.Spec.Reporter.Console (consoleReporter)
import Test.Spec.Runner (run)
import Test.Spec.Runner (runSpec)

main :: Effect Unit
main = launchAff_ $ run [consoleReporter] do
main = launchAff_ $ runSpec [consoleReporter] do
describe "purescript-spec" do
describe "Attributes" do
it "awesome" do
Expand Down Expand Up @@ -121,7 +121,7 @@ baseSpecs = do
```

This is often used to combine all specs into a single spec that can be passed
to the test runner, if not using [purescript-spec-discovery](https://github.com/owickstrom/purescript-spec-discovery).
to the test runner, if not using [purescript-spec-discovery](https://github.com/purescript-spec/purescript-spec-discovery).

## Running A Subset of the Specs

Expand All @@ -147,8 +147,196 @@ describe "Module" do
it "does feature Y" ...
```

There is also `focus` which can be used to select some specific group for execution

```purescript
describe "Module" do
describe "Sub Module A"
it "does feature X" ...
focus $ describe "Sub Module B" do -- all tests passed to focus will be executed
it "does feature Y" ...
it "does feature Z" ...
describe "Sub Module C" do
it "does feature P" ...
```



## QuickCheck

You can use [QuickCheck](https://github.com/purescript/purescript-quickcheck)
together with the [purescript-spec-quickcheck](https://github.com/owickstrom/purescript-spec-quickcheck)
together with the [purescript-spec-quickcheck](https://github.com/purescript-spec/purescript-spec-quickcheck)
adapter to get nice output formatting for QuickCheck tests.


## Parallel spec execution

You can use `parallel` to mark specs for parallel execution. This is useful
if you want to speed up your tests by not waiting for some async action
to resolve. so if you have:

```purescript
describe "delay" do
it "proc 1" do
delay $ Milliseconds 500.0
it "proc 2" do
delay $ Milliseconds 500.0
it "proc 3" do
delay $ Milliseconds 1000.0
```

It would take `2000 ms` to finish. But, by sticking in `parallel`, it would take `1000 ms`:

```diff
- describe "delay" do
+ describe "delay" $ parallel do
```

**NOTE** that if you are logging things to console, by using `parallel`
order of log messages is less deterministic. For example if you had:

```purescript
describe "delay" do
it "proc 1" do
log $ "start 1"
delay $ Milliseconds 500.0
log $ "end 1"
it "proc 2" do
log $ "start 2"
delay $ Milliseconds 500.0
log $ "end 2"
it "proc 3" do
log $ "start 3"
delay $ Milliseconds 1000.0
log $ "end 3"
```

you would see messages in this order:

```
start 1
end 1
start 2
end 2
start 3
end 3
```

but if you have used `parallel` then messages will come in this order:

```
start 1
start 2
start 3
end 1
end 2
end 3
```

`purescript-spec` itself is not providing any specific solution for this
issue but you can take a look at [/test/Test/Spec/HoistSpec.purs](https://github.com/purescript-spec/purescript-spec/blob/master/test/Test/Spec/HoistSpec.purs)
for some inspiration.

## Using hooks

`before_` runs a custom action before every spec item. For example, if you
have an action `flushDb` which flushes your database, you can run it before
every spec item with:

```purescript
main :: Spec Unit
main = before_ flushDb do
describe "/api/users/count" do
it "returns the number of users" do
post "/api/users/create" "name=Jay"
get "/api/users/count" `shouldReturn` 1

describe "when there are no users" do
it "returns 0" do
get "/api/users/count" `shouldReturn` 0
```

Similarly, `after_` runs a custom action after every spec item:

```purescript
main :: Spec Unit
main = after_ truncateDatabase do
describe "createUser" do
it "creates a new user" do
let eva = User (UserId 1) (Name "Eva")
createUser eva
getUser (UserId 1) `shouldReturn` eva

describe "countUsers" do
it "counts all registered users" do
countUsers `shouldReturn` 0
```

`around_` is passed an action for each spec item so that it can perform
whatever setup and teardown is necessary.

```purescript
serveStubbedApi :: String -> Int -> Aff Server
stopServer :: Server -> Aff Unit

withStubbedApi :: Aff Unit -> Aff Unit
withStubbedApi action =
bracket (serveStubbedApi "localhost" 80)
stopServer
(const action)

main :: Spec Unit
main = around_ withStubbedApi do
describe "api client" do
it "should authenticate" do
c <- newClient (Just ("user", "pass"))
get c "/api/auth" `shouldReturn` status200

it "should allow anonymous access" do
c <- newClient Nothing
get c "/api/dogs" `shouldReturn` status200
```

Hooks support passing values to spec items (for example, if you wanted
to open a database connection before each item and pass the connection in).
This can be done with `before`, `around` and `after`. Here's an example
for how to use `around`:

```purescript
openConnection :: Aff Connection
openConnection = ...

closeConnection :: Connection -> Aff Unit
closeConnection = ...

withDatabaseConnection :: (Connection -> Aff Unit) -> Aff Unit
withDatabaseConnection = bracket openConnection closeConnection

spec :: Spec Unit
spec = do
around withDatabaseConnection do
describe "createRecipe" do
it "creates a new recipe" $ \c -> do
let ingredients = [Eggs, Butter, Flour, Sugar]
createRecipe c (Recipe "Cake" ingredients)
getRecipe c "Cake" `shouldReturn` ingredients
```

Hooks support nesting too:

```purescript
spec :: Spec Unit
spec = do
before (pure 1) $ after (\a -> a `shouldEqual` 1) do
it "before & after usage" \num -> do
num `shouldEqual` 1
beforeWith (\num -> num `shouldEqual` 1 *> pure true) do
it "beforeWith usage" \bool -> do
bool `shouldEqual` true
aroundWith (\computation bool -> bool `shouldEqual` true *> pure "fiz" >>= computation <* pure unit) do
it "aroundWith usage" \str -> do
str `shouldEqual` "fiz"
beforeWith (\num -> num `shouldEqual` 1 *> pure (show num)) do
it "beforeWith" \str -> do
str `shouldEqual` "1"
```
7 changes: 4 additions & 3 deletions example/Main.purs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
module Main where

import Prelude

import Data.Time.Duration (Milliseconds(..))
import Effect (Effect)
import Effect.Aff (delay, launchAff_)
import Data.Time.Duration (Milliseconds(..))
import Test.Spec (pending, describe, it)
import Test.Spec.Assertions (shouldEqual)
import Test.Spec.Reporter.Console (consoleReporter)
import Test.Spec.Runner (run)
import Test.Spec.Runner (runSpec)

main :: Effect Unit
main = launchAff_ $ run [consoleReporter] do
main = launchAff_ $ runSpec [consoleReporter] do
describe "purescript-spec" do
describe "Attributes" do
it "awesome" do
Expand Down
Loading