elm-explorations / test Goto Github PK
View Code? Open in Web Editor NEWWrite unit and fuzz tests for Elm code.
Home Page: https://package.elm-lang.org/packages/elm-explorations/test/latest
License: BSD 3-Clause "New" or "Revised" License
Write unit and fuzz tests for Elm code.
Home Page: https://package.elm-lang.org/packages/elm-explorations/test/latest
License: BSD 3-Clause "New" or "Revised" License
Currently it appears to be impossible to use Fuzz.custom
, since it requires providing a Shrinker
but the only way to do that is to create one using the functions in the non-exposed Shrink
module.
Related: the documentation for Fuzz.custom
refers to:
elm-lang/random
: should be elm/random
, and "which is not core's Random module but has a compatible interface" should be removedeeue56/elm-shrink
, which does not existMinimal reproduction:
import Expect
import Fuzz
import Test exposing (..)
testRepro : Test
testRepro =
fuzz2 Fuzz.int (Fuzz.constant ()) "reproduce infinite recursion" <|
\i j -> Expect.equal True False
We need to use fuzz2
, we need a failing test, and using two constant fuzzers does not reproduce. It does not reproduce if the order of the fuzzers is switched.
Output:
โ reproduce infinite recursion
This test failed because it threw an exception: "RangeError: Maximum call stack size exceeded"
I don't know how long this issue has existed.
When generating random values from a fuzzer, there is no guarantee that each one will be unique. You may ask for 100 cases but get less. It may be possible you get much less.
One solution is to hash each input, store the hashes, and reject inputs with a duplicate hash. We'd need to fail the test after some number of failed attempts to create distinct inputs, perhaps max 20 (2*numberOfRequestedRuns)
.
Since we'd want a designated union type tag for this failure condition, it makes sense to do this while we're doing a major revision.
Is there any interest in exploring this idea?
Hi,
May I give a suggestion: rename the Shrinker
type to Simplifier
.
This is a suggestion that occurred to me whilst reading through #33 but I thought it worth making a new issue rather than derailing that one.
Following the (de-facto?) principle of using descriptive names in elm, I thought that the meaning of "shrinking a test input" would have been much clearer to me if it had instead been called "simplifying a test input".
From @mgold's comment: #33 (comment)
Let's say I have a test that claims every integer is even. You'll get around 50 failing tests, each with a different odd number. The goal of the shrinker is to tell you that 1 is the "smallest" or "simplest" counterexample to your claim. 1 is
"larger""smaller" than -1, somewhat by convention.
Feel free to close if such a change is not appropriate, or if github is not the appropriate place to make such a suggestion.
Cheers ๐
(Sorry if this isn't the right repository, I'm a little at a loss here...)
I have a set of tests in a private project that fails to run. I'm relatively certain that the failure does not represent a bug in the test or the code (i.e. I don't think it's rtfeldman/node-test-runner#290). I haven't tried boiling things down to an SSCCE yet, but will try next. (I wanted to make sure I didn't lose the stack traces.) Here are the error messages I've gotten:
> elm-test
elm-test 0.19.0-rev5
--------------------
Running 14 tests. To reproduce these results, run: elm-test --fuzz 100 --seed 396170984152586 [...]
#
# Fatal error in , line 0
# API fatal error handler returned after process out of memory
#
and
> elm-test
elm-test 0.19.0-rev5
--------------------
Running 14 tests. To reproduce these results, run: elm-test --fuzz 100 --seed 215354435481898 [...]
<--- Last few GCs --->
[17089:0x380a230] 141745 ms: Mark-sweep 1408.2 (1460.8) -> 1408.2 (1444.8) MB, 3321.9 / 0.0 ms (+ 0.0 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 3322 ms) last resort
[17089:0x380a230] 145181 ms: Mark-sweep 1408.2 (1444.8) -> 1408.2 (1444.8) MB, 3435.9 / 0.0 ms last resort
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x219007da8799 <JSObject>
1: /* anonymous */ [/home/ethan/src/quartermaster/frontend/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:~10389] [pc=0x467f709e9e1](this=0xd99f2d746f1 <JSFunction (sfi = 0x13127ca2071)>,hour=10,minute=26,second=23)
2: /* anonymous */(aka /* anonymous */) [/home/ethan/src/quartermaster/frontend/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:~10416] [pc=0...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [/home/ethan/.nvm/versions/node/v8.5.0/bin/node]
2: 0x13576dc [/home/ethan/.nvm/versions/node/v8.5.0/bin/node]
3: v8::Utils::ReportOOMFailure(char const*, bool) [/home/ethan/.nvm/versions/node/v8.5.0/bin/node]
4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/home/ethan/.nvm/versions/node/v8.5.0/bin/node]
5: v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [/home/ethan/.nvm/versions/node/v8.5.0/bin/node]
6: v8::internal::Runtime_AllocateInTargetSpace(int, v8::internal::Object**, v8::internal::Isolate*) [/home/ethan/.nvm/versions/node/v8.5.0/bin/node]
7: 0x467f6f046fd
After either message, elm-test
hangs (doesn't finish in 6-7 minutes) and I have to kill it with Ctrl-C.
Rerunning the tests with the same seed causes the same message, but rerunning the tests with a new seed can produce either message or even succeed after a very long time (~3 min vs. the usual ~15 seconds).
Although the message is about OOMing, my computer still has plenty of free RAM (~2GB according to top
). I'm guessing node is exhausting some pre-allocated heap, but I couldn't figure out how to enlarge that heap (unlike e.g. #22 (comment)).
I suspect there's something about my tests and/or fuzzers that consume an awful lot of memory but I haven't figured out exactly what it is. When I try to disable certain parts of my fuzzers I can circumvent the error. In particular, I have had a lot of success converting Fuzz.list a
into Fuzz.map (\elem -> [elem]) a
. Of course this limits the utility of the test.
elm-html-test
was incorporated into this library, but the documentation in elm-html-test
's README hasn't been moved over yet.
elm-html-test
's latest README should be incorporated into this projects documentation somehow.
There seems to be a version conflict with elm-test and elm/file
, to reproduce:
mkdir elm-test-bug
cd elm-test-bug
elm init
elm-test init
elm-test
; this workselm install elm/file
elm-test
fails because somehow the dependencies are not compatibleAdditionally, adding elm-explorations/test
as a dependency works just fine, so it looks like the problem is in elm-test itself.
So, I've been trying to use the Fuzz.custom
function to work around the disappearance of Fuzz.conditional
and Fuzz.andThen
on a pre-existing codebase that I'm trying to migrate ; and I saw that I needed a Random.Generator
(good, I know what they do is generate stuff randomly in a functionally pure way, and can work on one of those with Random.andThen
and Random.map
and other niceties) and a Shrink.Shrinker
.
Ok, let's read the docs on this last one... those excerpts from the doc seem relevant:
If the fuzzer can make your test fail, it also knows how to "shrink" that failing input into more minimal examples, some of which might also cause the tests to fail.
Well, looks like it's a thing that does something called "shrinking" on a failing sample. Shrinking sounds like it's making things smaller. And this "shrunk" sample should attempt to make the sample fail. So far, so good.
type alias Shrinker a =
a -> LazyList a
The shrinker type. A shrinker is a function that takes a value and returns a list of values that are in some sense "smaller" than the given value. If there are no such values conceptually, then the shrinker should just return the empty list.
So, it's an alias for a function that takes a value and returns a fancy list of values, not just one, and they need to be "smaller". What does "smaller" means in this context? Like, 0 is smaller than 1? -1 is smaller than 0? "" is smaller than "a"? Is "Z" smaller than "z"? Is "aa" smaller than "z"?...
Also, why is the word "conceptually" in this sentence?
Oh, there's another function that may make this make more sense:
shrink : (a -> Bool) -> Shrinker a -> a -> a
Perform shrinking. Takes a predicate that returns True if you want shrinking to continue (e.g. the test failed). Also takes a shrinker and a value to shrink. It returns the shrunken value, or the input value if no shrunken values that satisfy the predicate are found.
Still not sure what shrinking really is, but let's read on... Why would I want shrinking to continue, or stop? This predicate doesn't take the test as an input, why would "the test failed" be an example? Should I pass a predicate that internally reference my test itself? It returns the shrunken value. Why only one? I thought shrinkers could return multiple shrunken values? Which one will be selected?
Ok, that didn't help much. Let's see what's next. Oh, a list of shrinker constructors for many types... ok, I could use some of them if I was sure they did what I want. But I don't know what I want yet. Let's see what's next...
convert : (a -> b) -> (b -> a) -> Shrinker a -> b -> LazyList b
Convert a Shrinker of a's into a Shrinker of b's using two inverse functions. ) [...]
Ok, I see the Shrinker a
; where is the Shrinker b
? Oh, right, it's the b -> LazyList b
that's synonymous at the end of the signature...
Then I see:
[...] If you use this function as follows:
shrinkerB =
f g shrinkerA
Make sure that
`f(g(x)) == x` for all x
Or else this process will generate garbage.
Wait... what? What is f
? What is g
? Why would I use f g shrinkerA
? Where does it have to do with convert
? It will generate garbage unless f(g(x)) == x for all x
? I thought f
was a function that took two arguments (g
and shrinkerA
) so why does it takes only one in the f(g(x)) == x
law? Is x a function too?
I'll stop here, I guess you understand my point: this is confusing for someone who doesn't already know what shrinkers are, what they're meant to do, and why we need them to work with the Generators to make Fuzzers. And this is kinda important for someone who wants to make their own Fuzzers to understand them, especially when functions like Fuzz.andThen
and Fuzz.conditional
are deprecated.
Since I'd rather help than give someone else work, I'd love to write a documentation that takes the user by the hand when they try to wrap their head around the subject, but I'd have to understand what Shrinkers are, what they do and why first (and right now, it's still quite fuzzy for me :p).
So, if someone in this fine team would like to take a moment and help me get the basics on Fuzzers so I can send a documentation PR, I'd be happy to do just that in return ;)
This was removed in 0.19, should be updated. https://github.com/elm-explorations/test/blob/1.2.0/src/Shrink.elm#L527-L532
This might be the same problem as #22 or rtfeldman/node-test-runner#290 but here with very simple data which seems to point to a problem with output string diffing.
So, the following:
sscce : Test
sscce =
test "Different long strings" <|
\_ ->
String.repeat 1000 "a"
|> Expect.equal (String.repeat 1000 "b")
causes
Tests.elm changed. Rebuilding!
elm-test 0.19.0-beta12
----------------------
Running 1 test. To reproduce these results, run: elm-test --fuzz 100 --seed 354267269012927 /home/nonpop/projects/elm/sscce/tests/Tests.elm
/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:579
function _Utils_eqHelp(x, y, depth, stack)
^
RangeError: Maximum call stack size exceeded
at _Utils_eqHelp (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:579:23)
at _Utils_eq (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:570:35)
at /home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3452:9
at Function.f (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3493:5)
at A5 (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:113:28)
at /home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3497:13
at Function.f (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3434:11)
at A2 (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:104:28)
at Function.f (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3494:11)
at A5 (/home/nonpop/projects/elm/sscce/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:113:28)
Everything works if I make the strings the same by just changing "b" to "a".
In some cases having keyed html nodes makes a functional difference, so we want to test for it.
I'd like to write something like
test "Keyed Button has the expected key" <|
\_ ->
Html.Keyed.node "button" [] [ ( "key1", Html.text "I'm a button!" ) ]
|> Query.fromHtml
|> Query.has [ Selector.key "key1" ]
There's already #34 which is about running tests that live in a non-standard directory. Fortunately, this can now be easily done through elm-test path/to/that/dir
.
I believe that ultimately there should be a way to specify the custom paths for tests in a config file. If elm-test
allows you to run tests that are not in <root_dir>/tests
, then I think it should also allow for specifying that custom paths in elm.json
so that 3rd party tools can support that use case as well.
Let me explain my specific scenario: @altaurog added support for 0.19 in ale (a vim plugin) in dense-analysis/ale#2176 (thanks for that!) which corresponds to the issue #64. The code assumes that tests are at <root_dir>/tests
. We have a Rails app with frontend in Elm and the Elm tests live in app/javascript/tests
, so that fix doesn't work for me in that project.
In our scenario we can freely move those Elm tests to <root_dir>/tests
, but I imagine that in the future someone won't have this luxury.
This is just the first thing that came to my mind, perhaps there are other ways to solve this problem and I'm open to hear them!
Hi,
I'm trying to migrate a library on Elm 0.19.0 and my tests were relying on Fuzz.conditional
to tests cases where an input was "anything but" specific values (ie: I want any integer that is not a multiple of 3 ; I want any string that does not contain some substrings).
I used to do it like this:
Fuzz.conditional
{ retries = 10
, fallback = always 1
, condition = \n -> (n |> modBy 3) == 0
}
int
Can I do this now? If so, how can I do this now? If not, am I the only one to use that kind of strategy? If so, how do you use fuzzy testing to test those kinds of cases?
I have a working version of sortedList : List a -> Fuzz (List a)
that generates versions of a list with different sort ordering; however, it depends on Random.List.shuffle
from elm-community/random-extra
:
shuffle : List a -> Fuzzer (List a)
shuffle list =
Fuzz.custom (Random.List.shuffle list) Shrink.noShrink
I think it's pretty useful to be able to fuzz test that different sort orderings of a list produce the same outcome, so I'd love to have first class support for it.
With a fresh project under elm 0.19...
npm install -g elm-test
command installs elm-test 0.18.13-beta. https://www.npmjs.com/package/elm-test
When I run elm-test init
I get the following error:
Created /home/cbass/Projects/projelm/tests
Created /home/cbass/Projects/projelm/tests/elm-package.json
Created /home/cbass/Projects/projelm/tests/Example.elm
/home/cbass/Projects/projelm/.gitignore already exists
/bin/sh: elm-package: command not found
Unhandled exception while running the tests: { Error: Command failed: elm-package install --yes
at checkExecSyncError (child_process.js:611:11)
at Object.execSync (child_process.js:648:13)
at runElmTest (/home/cbass/.nvm/versions/node/v10.10.0/lib/node_modules/elm-test/lib/elm-test.js:291:19)
at Object.<anonymous> (/home/cbass/.nvm/versions/node/v10.10.0/lib/node_modules/elm-test/lib/elm-test.js:742:1)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
status: 127,
signal: null,
output: [ null, null, null ],
pid: 4881,
stdout: null,
stderr: null }
Kinda confused?
Also started a thread here (https://elmlang.slack.com/archives/C192T0Q1E/p1537193358000100) but not sure if right place for this
When running elm-test
on my CI running alpine Linux it fails like so:
$ elm-test
events.js:183
throw er; // Unhandled 'error' event
^
Error: spawn /opt/app/waive/assets/node_modules/elmi-to-json/unpacked_bin/elmi-to-json ENOENT
at _errnoException (util.js:992:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:190:19)
at onErrorNT (internal/child_process.js:372:16)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
at Function.Module.runMain (module.js:695:11)
at startup (bootstrap_node.js:191:16)
at bootstrap_node.js:612:3
Exited with code 1
I connect and check that file it does exist and has the right permissions, but attempting to run it results in bash: /opt/app/waive/assets/node_modules/elmi-to-json/unpacked_bin/elmi-to-json: No such file or directory
.
I believe this is due to Alpine Linux's use of musl over libc. The elmi-to-json binary is not statically linked and assumes that libc is present, so it cannot be run.
It's common to use Alpine Linux when using Docker as it currently provides the smallest images available, so it would be beneficial for elm-test
to work on this distribution.
https://package.elm-lang.org/packages/elm-explorations/test/latest/Shrink#lazylist
The function Simplify.lazylist
has this type signature (note it takes a LazyList
as an argument):
lazylist : Shrinker a -> LazyList a -> LazyList (LazyList a)
However, LazyList
is not exposed by this package so there is no way that a user can get their hands on a LazyList
to pass to Simplify.lazylist
. Therefore, (unless I am wrong - entirely possible) there is no way to call this function.
Either:
LazyList
Just trying to get this working over v19.
I noticed that even though:
elm.json
at the root of my projectProblem: When I run elm-test init
it creates a test
directory but in that directory I only see:
elm-package.json
(why isn't it elm.json ??????)
Example.elm
For troubleshooting, ran npm install -g elm-test
again and it appears to have installed the new elm-test for v19 as you can see at the bottom...although I don't know if the prior lines in the install results there are "normal":
However after running elm-test init
, something isn't right here.
Created /Users/daveschinkel/Code/katas/minMax/elm-minmax-kata/tests
Created /Users/daveschinkel/Code/katas/minMax/elm-minmax-kata/tests/elm-package.json
Created /Users/daveschinkel/Code/katas/minMax/elm-minmax-kata/tests/Example.elm
/Users/daveschinkel/Code/katas/minMax/elm-minmax-kata/.gitignore already exists
/bin/sh: elm-package: command not found
Unhandled exception while running the tests: { Error: Command failed: elm-package install --yes
at checkExecSyncError (child_process.js:603:11)
at Object.execSync (child_process.js:640:13)
at runElmTest (/usr/local/lib/node_modules/elm-test/lib/elm-test.js:291:19)
at Object.<anonymous> (/usr/local/lib/node_modules/elm-test/lib/elm-test.js:742:1)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
status: 127,
signal: null,
output: [ null, null, null ],
pid: 14555,
stdout: null,
stderr: null }
That creates a test folder but with an elm-package.json in it, not elm.json.
When updating some of my tests to use this package, I ran into a few places where I was using Test.fuzz4
. My initial solution was to use Fuzz.map4
to map the four arguments into a record, and rewrite my expectation function to take a single record argument, but this seemed pretty messy (introduced some pretty meaningless record types). I ended up writing my own module to replicate Test.fuzz4
:
module Test.FuzzN exposing (fuzz4)
import Expect exposing (Expectation)
import Fuzz exposing (Fuzzer)
import Test exposing (Test)
type alias Arguments4 a b c d =
{ argument1 : a
, argument2 : b
, argument3 : c
, argument4 : d
}
fuzz4 : Fuzzer a -> Fuzzer b -> Fuzzer c -> Fuzzer d -> String -> (a -> b -> c -> d -> Expectation) -> Test
fuzz4 fuzzer1 fuzzer2 fuzzer3 fuzzer4 description expectation =
Test.fuzz
(Fuzz.map4 Arguments4 fuzzer1 fuzzer2 fuzzer3 fuzzer4)
description
(\{ argument1, argument2, argument3, argument4 } ->
expectation argument1 argument2 argument3 argument4
)
(The actual module also implements fuzz5
for completeness.) I realize that Test.fuzz4
and Test.fuzz5
can no longer be described as alternatives to Fuzz.tuple4
and Fuzz.tuple5
, so the documentation wording would need to be updated, but I think it makes sense to continue to support them (just like Fuzz.map4
and Fuzz.map5
are still supported).
Thoughts? Would a pull request be welcome? If so, is the above implementation a good one? (Wasn't sure if it might cause issues for shrinking or error message generation, for example...)
As hinted at on Discourse, there was a plan to add Cmd
testing to elm-test
.
While there are ways to test effects right now, they involve a lot of boilerplate and indirection, and it seems most appropriate to be able to compare Cmd
s directly, when it comes to tests.
I opened this issue mainly to track the status of this idea. Is there a concrete plan for this?
The documentation in Shrink.elm
v1.2.0 says about this topic
Shrinkers have to return a LazyList
. . . but unfortunately with corresponding types (or helper functions) are not exposed, making it for some cases hard to write a Shrinker
.
While many custom shrinkers can be easily composed by using the provided shrinkers and helper functions, this is not the case for ADTs (like type abc = A | B | C
) - at least I haven't found a way to do this.
My current use case is very similar to creating a shrinker for Maybe
- just for a custom type.
Please expose appropriate functions to achieve this and/or adjust the documentation to more elaborately explain creating custom shrinkers.
Edit:
I finally achieved my goals by composing Fuzzers (instead of Shrinkers - in so far it was my fault).
Nevertheless, the documentation for this topic seems misleading (since elm 0.19) as the given advice can't be followed because the mentioned type LazyList
is no longer exposed.
For several reasons...
Cmd
values anyway...the plan is to add elm-html-test
here.
This will entail the usual 0.19 changes, plus Native
-> Kernel
, and updating the README and other docs.
As mentioned in #89, I'm a fan of hedgehog
.
hedgehog
comes with a useful set of generators for characters and for strings too, such as (as would be written in Elm):
lower : Fuzzer Char
alphaNum: Fuzzer Char
These are great building blocks for larger fuzzers, as the generator for strings has the form (ignoring Range
, discussed separately in #89):
string : Fuzzer Char -> Fuzzer String
Thus allowing the user to choose what class of characters to use when generating a list string.
In many cases all printable Unicode characters are invalid input.
Even if you represented valid strings safely using type MyAlphaString = MyAlphaString String
. Writing a fuzzer for MyAlphaString
is not straightforward.
Would you accept a PR in this direction? or prefer it as a separate package?
Should we add syntactic sugar to test input-to-expected-result tables?
Jest
recently included describe.each
and test.each
. Could it work for elm-test
?
test.each([[1, 1, 2], [1, 2, 3], [2, 1, 3]])(
'.add(%i, %i)',
(a, b, expected) => {
expect(a + b).toBe(expected);
},
);
Polymorph in its argument: testEach : String -> List a -> (a -> Expect.Expectation) -> List Test
module SearchTest exposing (all)
import Expect
import Search exposing (Filter(..), toFilters)
import Test exposing (Test, describe, test)
-- usage example
all : Test
all =
describe "Search"
[ describe "test toFilters"
(testEach "toFilters"
[ ( "", [] )
, ( " ", [] )
, ( "a", [ TextFilter "a" ] )
, ( "a b", [ TextFilter "a", TextFilter "b" ] )
]
<|
\( a, b ) ->
a
|> toFilters
|> Expect.equal b
)
]
-- test each implementation
testEach : String -> List a -> (a -> Expect.Expectation) -> List Test
testEach name table fn =
let
toTest item =
let
testName =
name ++ " for input " ++ toString item
in
test testName <|
\_ ->
fn item
in
List.map toTest table
Would work with fixed tuples. testEach : String -> List ( a, b ) -> (a -> b) -> List Test
module SearchTest exposing (all)
import Expect
import Search exposing (Filter(..), toFilters)
import Test exposing (Test, describe, test)
-- usage example
all : Test
all =
describe "Search"
[ describe "test toFilters"
(testEach "toFilters"
[ ( "", [] )
, ( " ", [] )
, ( "a", [ TextFilter "a" ] )
, ( "a b", [ TextFilter "a", TextFilter "b" ] )
]
toFilters
)
]
-- test each implementation
testEach : String -> List ( a, b ) -> (a -> b) -> List Test
testEach name table fn =
let
toTest (( input, expectedResult ) as tuple) =
let
testName =
name ++ " for input " ++ toString tuple
in
test testName <|
\_ ->
fn input |> Expect.equal expectedResult
in
List.map toTest table
Expect.equal
only?I'm running into an issue where the following test case is failing when, based on the documentation for the has
and hasNot
functions, it should be passing. The following is the test case itself and after is the relevant console log.
table
|> Query.fromHtml
|> Query.find [ Selector.tag "thead" ]
|> Query.find [ Selector.tag "tr" ]
|> Query.hasNot [ Selector.attribute (Aria.colIndex 1) ]
> Table
> colindex on tr
> is not added for a non contiguous heading list
โผ Query.fromHtml
<table aria-colcount="5" aria-rowcount="1">
<thead>
<tr>
<th aria-colindex="1">
label
</th>
<th aria-colindex="3">
label
</th>
<th aria-colindex="5">
label
</th>
</tr>
</thead>
<tbody>
<tr aria-rowindex="2">
</tr>
</tbody>
</table>
โผ Query.find [ tag "thead" ]
1) <thead>
<tr>
<th aria-colindex="1">
label
</th>
<th aria-colindex="3">
label
</th>
<th aria-colindex="5">
label
</th>
</tr>
</thead>
โผ Query.find [ tag "tr" ]
1) <tr>
<th aria-colindex="1">
label
</th>
<th aria-colindex="3">
label
</th>
<th aria-colindex="5">
label
</th>
</tr>
โผ Query.hasNot [ attribute "aria-colindex" "1" ]
> has not attribute "aria-colindex" "1"
My thought is that this would pass because the tr
tag does not have a aria-colindex
attribute. This is a similar case shown in the documentation for the package, but is not executing as expected. After playing with it a bit I figure out that it was due to the fact that there was a child th
element that did have a aria-colindex="1"
which makes the test fail. The only way I've been able to get around this issue is to modify the table's structure to not include the child th
tags, but this is not ideal.
I'm kind of asking 2 questions here which is
The logic elm-test
uses to identify floats incorrectly identifies a union type with a potential value of Infinity
as a float. This is because String.toFloat "Infinity" == Just Infinity
.
This error only happens when the name of the union potential value is Infinity
.
module Example exposing (..)
import Expect exposing (Expectation)
import Fuzz exposing (Fuzzer, int, list, string)
import Test exposing (..)
type UnionType =
Infinity
suite : Test
suite =
test "should not give a 'use float' error" <|
\() ->
Infinity
|> Expect.equal Infinity
Running elm-test
with the latest (beta) version gives:
Running 1 test. To reproduce these results, run: elm-test --fuzz 100 --seed 241676437961883
โ Example
โ should not give a 'use float' error
Do not use Expect.equal with floats. Use Float.within instead.
I do not know what the solution is for this, I just renamed my union types as a work around.
Hi,
The readme still talks about elm-package.json, even thought 0.19 uses elm.json files. And it still talks about copying dependencies between your main and test elm-package.json files, even though we can use one elm.json in 0.19
I would make the PR myself, but I am currently trying to figure out how to do tests with 0.19 myself, so I dont really know how to instruct others.
This section seems to be out of date https://github.com/elm-explorations/test#from-310 since the version has been reset with the move to elm-explorations
.
Since we only have two sizes of tuples, I feel like we could see if we can give the two distinct names. Thoughts?
The README links to https://github.com/elm-community/html-test-runner which does not support 0.19 and there doesn't seem to be much movement adding support for it (see elm-community/html-test-runner#9).
I think it might be worth removing this link until either html-test-runner adds support for 0.19, or another way of running tests in a browser is added as to not mislead folks that are new to elm-test.
Thoughts? :-)
The documentation for Fuzz.int
states that it generates any 32 bit signed integer value but I've found that it can generate the value 2147483648 which is one greater than largest maximum Int32 value.
elm-test version: 1.2.0
OS: Windows 10
I always install Elm locally in my projects and run it from ./node_modules/.bin
. For this to work with elm-test
I use the --compiler
flag, though it seems this doesn't work with the elm-test init
command.
$ ./node_modules/.bin/elm-test init --compiler ./node_modules/.bin/elm
/bin/sh: 1: elm: not found
Unable to create temporary directory for elm-test install. { Error: Command failed: elm install elm-explorations/test
at checkExecSyncError (child_process.js:603:11)
at Object.execSync (child_process.js:640:13)
at Object.install (/home/louis/src/waive/assets/node_modules/elm-test/lib/install.js:54:19)
at Object.<anonymous> (/home/louis/src/waive/assets/node_modules/elm-test/lib/elm-test.js:160:11)
at Module._compile (internal/modules/cjs/loader.js:702:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
at Module.load (internal/modules/cjs/loader.js:612:32)
at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
at Function.Module._load (internal/modules/cjs/loader.js:543:3)
at Module.require (internal/modules/cjs/loader.js:650:17)
at require (internal/modules/cjs/helpers.js:20:18)
at Object.<anonymous> (/home/louis/src/waive/assets/node_modules/elm-test/bin/elm-test:3:1)
at Module._compile (internal/modules/cjs/loader.js:702:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
at Module.load (internal/modules/cjs/loader.js:612:32)
at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
at Function.Module._load (internal/modules/cjs/loader.js:543:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:744:10)
at startup (internal/bootstrap/node.js:238:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:572:3)
status: 127,
signal: null,
output: [ null, null, null ],
pid: 6077,
stdout: null,
stderr: null }
What's the recommended method for using elm-test init
without globally install Elm?
I stumbled across this crash when I migrated one of my Elm projects to 0.19. This is the test I wrote with Elm 0.18, where it worked without problems: https://gitlab.com/MazeChaZer/knobster/blob/8d39fa8de9f5744cdaff45755b23050f4d9d06e0/tests/GridTest.elm
elm: 0.19.0
elm-explorations/test: 1.1.0
node-test-runner: 0.19.0-beta8
SSCCE:
module Example exposing (suite)
import Expect
import Test exposing (..)
suite : Test
suite =
test "foo bar" <|
\() ->
Expect.equal
[ [ { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
]
, [ { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
]
, [ { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
]
, [ { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
]
, [ { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
]
, [ { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
, { foo = "foo", bar = "bar" }
]
]
[]
Output:
$ elm-test
Success!
Success! Compiled 1 module.
elm-test 0.19.0-beta8
---------------------
Running 1 test. To reproduce these results, run: elm-test --fuzz 100 --seed 195384286911629
[project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3665
var change = function () {
^
RangeError: Maximum call stack size exceeded
at [project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3665:26
at Function.f ([project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3707:5)
at A5 ([project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:113:28)
at [project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3711:13
at Function.f ([project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3648:11)
at A2 ([project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:104:28)
at Function.f ([project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3708:11)
at A5 ([project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:113:28)
at [project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3711:13
at Function.f ([project]/elm-stuff/generated-code/elm-explorations/test/elmTestOutput.js:3648:11)
There was an unexpected runtime exception while running tests
A normal ==
comparison is no problem with this data structure: https://ellie-app.com/3fQ2FSpkxYca1
It's nontrivial to get Fuzz.andThen
working in 0.19 because the 0.18 version implementation relied on Debug.crash
.
Perhaps we should re-add Fuzz.andThen
as a MINOR
release, with more helpful error messages in the event that you give it an invalid fuzzer.
I'm a fan of hedgehog
[1] and I think it gets a lot of things right.
One of those is having a Range
parameter for all fuzzers (i.e. Gen
s) that generate values with some notion of a range: integers, floats, strings, lists and other collection types.
Thus, there is no int : Fuzzer Int
.
Only int : Range Int -> Fuzzer Int
.
In hedgehog
, internally a Range
is defined as (translated to Elm):
type Size
= Size Int
type Range a
= Range a (Size -> ( a, a ))
Here Size
is essentially the number of runs.
In Range a boundsFunction
:
a
is the "origin" valueboundsFunction
shrinks towards this "origin" a
as Size
goes down (example defaults are 0
for Int
s, empty list for lists)See [2] for a comment about how I understand Size
being used in boundsFunction
.
To construct a Range Int
, you would use:
linear : Int -> Int -> Range Int
linear lo hi =
linearFrom lo lo hi
linearFrom : Int -> Int -> Int -> Range Int
linearFrom origin lo hi =
Range origin (intBoundsFunction origin lo hi)
intBoundsFunction : Int -> Int -> Int -> (Size -> (Int, Int))
-- Not elaborated on purpose, you can see hedgehog source for how it's done in Haskell
IMO this has several advantages:
boundsFunction
, it's useful to look at the hedgehog
source [3] to see how they do this using linear
, linearFrom
, exponential
and exponentialFrom
constructor functions.I understand that a more flexible and powerful API also results in a more "complicated" API, and you might be trying to go with something simple and uncomplicated.
Hence posting this issue to gauge appetite.
runs >= 99
the full range is generated, otherwise it is scaled down. So basically the range saturates at Size 99
.As far as I can tell, there is no way to customize the path where the tests are.
Previously, we could use the elm-test TESTFILES
option, but that seems to look for tests
directory now.
For example:
elm-test src/test/elm/**/*.elm
Error: /.../src/test/elm/tests does not exist. Please create a tests/ directory in your project root!
It would be nice if we could specify in elm.json: test-directories
similar to source-directories
option.
https://package.elm-lang.org/packages/elm-explorations/test/latest/Test-Html-Selector#attribute
The link points to @eeue56's package - maybe move that over to this package and link to itself?
Lines 747 to 748 in f42d322
This creates some problems with elm-verify-examples
. See stoeffel/elm-verify-examples#83. Perhaps there could be a command line switch or something like Expect.strictlyEqual
to allow to do this kind of comparison.
For reference here is a discussion that introduced this feature: elm-community/elm-test#230
Test.Runner.Failure.format
says it's deprecated. This is a reminder to remove it in the next major release.
I gather that test-dependencies
has been added to elm.json
(formerly elm-package.json
) to separate test dependencies. This does indeed seem to be a better approach than maintaining tests/elm.json
separately.
However, when using vim/ALE, I see import errors. ALE runs elm make
under the hood. It looks to me like it is essentially:
$ elm make --output=/dev/null tests/Example.elm
Which produces the following error
-- UNKNOWN IMPORT -------------------------------------------- tests/Example.elm
The Example module has a bad import:
import Test
I cannot find that module! Is there a typo in the module name?
The "source-directories" field of your elm.json tells me to look in directories
like src, but it is not in any of them. Maybe it is in a package that is not
installed yet?
Of course, elm-explorations/test is in test-dependencies
, not dependencies
.
By creating tests/elm.json
with adjusted source-directories
and dependencies
, I can get the make command (and thereby ALE) to work. But this confuses elm-test
and it fails with the following:
Error: /path/to/my/project/tests/tests does not exist. Please create a tests/ directory in your project root!
As a quick and dirty workaround, I have a bash function as follows:
elmtest() {
mv tests/elm.json tests/elmjson
elm-test "$@"
mv tests/elmjson tests/elm.json
}
But this is obviously not the right solution.
Is there a (better) way to do this now?
SSCCE:
module Example exposing (suite)
import Expect
import Fuzz
import Test exposing (..)
suite : Test
suite =
fuzz2 Fuzz.float (Fuzz.floatRange -1.0e100 1.0e100) "should not run out of stack" <|
\a b ->
Expect.fail "always fail"
Test to fail
elm-test 0.19.0-beta8
---------------------
Running 1 test. To reproduce these results, run: elm-test --fuzz 100 --seed 48737553166794
โ Example
โ should not run out of stack
This test failed because it threw an exception: "RangeError: Maximum call stack size exceeded"
floatRange
to float
fixes this.@avh4 did a great job moving elm-html-test
into elm-explorations/test
(thx ๐ ).
If I'm not mistaken the README.md
of that package got lost. It explains the general usage of the package.
We could:
The issue is similar to this one: #24
We have a model containing a Process.Id
(so that we can kill/restart it), but there is no way to create one for testing, since the Platform
module don't export the constructor, which makes perfectly sense when you target production code, but not in the context of testing.
A very generic solution to this kind of problems would be to add conditional compilation, so that instead of:
module Platform exposing
( Program
, ...
, ProcessId
, ...
)
We could write:
module Platform exposing
( Program
, ...
# if env == test then
, ProcessId(..)
# else
, ProcessId
# end
, ...
)
Notice that this would solve a lot of other problems (like #24, Debug.log
calls, etc...).
Any Html test I run fails with the message below
โผ Query.fromHtml
Internal Error: failed to decode the virtual dom.
Please report this at <https://github.com/elm-explorations/test/issues>.
Problem with the value at json.e[2].e[0].e[0].k.e[0].e[0].k:
undefined
Expecting an OBJECT with a field named `$`
โผ Internal Error: failed to decode the virtual dom.
Please report this at <https://github.com/elm-explorations/test/issues>
โผ Problem with the value at json.e[2].e[0].e[0].k.e[0].e[0].k:
undefined
Expecting an OBJECT with a field named `$`
The test is:
describeHeaders =
[ describe "headers"
[ test "should contain a container with three child divs" <|
\() ->
view model
|> Query.fromHtml
|> Query.findAll [ class "header" ]
|> Query.index 0
|> Query.has [ text "Score" ]
]
]
but I've got the same error whatever the test is.
I have a test where I move an item from a custom collection into another (this neccessitates changing IDs, which is why it is a special function). I generate two lists of strings to be converted into my collection and then grab a random index from the first collection to be moved into the second.
To determine the index of the item to move, I use a percentage
fuzzer. However, the test fails because of the edge case of the percentage being 1, where floor
ing the List.length * percent
doesn't help and neccessitates an extra conditional to work around the edge case.
I feel like there might be a more elegant way to choose an index. But I also think that exclusive range fuzzers might be useful in other situations as well, so I thought that this use case might motivate discussion around them.
When using Browser.application I will put the Key in my model for later use.
When testing I want to create a model, but I don't have a way to get a Key.
So I cannot test functions that take my Model.
Can test provide a way to get a navigation key?
Originally opened this here elm/browser#30
When viewing a diff, I frequently forget which one is the actual value and which the expected one.
There are two similar alternatives that are popular that both use the pipe operator in the display and that are both compatible with the reasoning that the current output is based on:
"first value"
โท
โ |> Expect.equal
โต
"second value"
"first value"
|> Expect.equal
"second value"
In order to play around with alternatives, check out the Ellie.
If you have a file like tests/Foo/BarSpec.elm
but that file starts with module BarSpec
then the tests defined in it won't run. Changing the file to start with module Foo.BarSpec
runs the tests as expected.
Someone suggested simulating event bubbling in html tests.
The basic idea would be:
<div onClick=...><button/></div>
in my vdom<button/>
onClick
handler on the parent <div>
would trigger in the real world, I should be able to write a test verifying that it triggeredIn this world, presumably stopPropagation
would need to be processed and handled properly.
Thoughts?
I think my case may be another +1 for #17, but perhaps there's another way to go about this.
How should one formulate fuzz tests with the dependence of one maybe type on another type?
My case:
type Position
= Delta Int Int (List Int)
| Coordinate Float Float (List Float)
type alias Transform =
{ ... }
fuzzTransform : Fuzzer (Maybe Transform)
fuzzPosition : Fuzzer Position
I'd like to pattern match the fuzzTransform
in the fuzzPosition
fuzzer, perhaps like this:
fuzzPosition : Maybe Transform -> Fuzzer Position
fuzzPosition transform =
case transform of
Just _ ->
fuzzDelta
Nothing ->
fuzzCoordinate
I don't see how to do this without Fuzz.andThen
, nor if I were to use a custom fuzzer. Is there a way to perhaps use something like:
fuzzTransform : Fuzzer Transform
fuzzPosition : Fuzzer Position
fuzzPosition =
Fuzz.frequency
[ ( 1, positionHelper Nothing )
, ( 3, positionHelper (Just fuzzTransform) )
]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.