I have just upgraded Specs2 on my project and now some specs won't compile and it isn't clear why they're not, here's the spec:
"fail validation if a connection is disconnected" in {
val connection = factory.create
awaitFuture(connection.disconnect)
factory.validate(connection) match {
case Failure(e) => ok("Connection successfully rejected")
case Success(c) => failure("should not have come here")
}
}
(The whole file can be seen here)
And the compiler says:
could not find implicit value for evidence parameter of type
org.specs2.execute.AsResult[Product with Serializable]
"fail validation if a connection is disconnected" in {
^
And while I understand what it is saying, it doesn't make any sense given I am returning ok or failure and I'm covering all cases on my match.
Any idea what could be wrong here?
The compiler is trying to find the common type of the 2 match branches. The first line is using ok which is a MatchResult and the second line is using failure which is returning a Result. Their only common type is Product with Serializable.
The fix is simply to use the opposite value of ok which is ko:
factory.validate(connection) match {
case Failure(e) => ok("Connection successfully rejected")
case Success(c) => ko("should not have come here")
}
You could also write
import org.specs2.execute._
...
factory.validate(connection) match {
case Failure(e) => Success("Connection successfully rejected")
case Success(c) => failure("should not have come here")
}
There is however no success(message: String) method available to match the corresponding failure. I will add it to the next specs2 version for better symmetry.
Related
I have a fairly simply unit test which has been working without issue for a long time.
It has suddenly started failing.
When I run/debug the unit test in vscode the test succeeds.
When I run the test from the cli it succeeds on windows but not on linux.
dart run test -j1 test/src/functions/ask_test.dart
Which is kind of interesting as there is nothing windows/linux specific.
The test has also been working for a long time on linux.
test('ask.any - throws', () {
final validator = Ask.any([
Ask.fqdn,
Ask.ipAddress(),
Ask.inList(['localhost'])
]);
expect(
() => validator.validate('abc'),
throwsA(predicate<AskValidatorException>((e) =>
e is AskValidatorException && e.message == 'Invalid FQDN.')));
});
The test gives the following error:
Error: Expected: throws satisfies function
Actual: <Closure: () => String>
Which: threw AskValidatorException:<Invalid FQDN.>
stack package:dcli/src/functions/ask.dart 760:7 _AskValidatorAny.validate
test/src/functions/ask_test.dart 65:25 main.<fn>.<fn>
package:test_api expect
test/src/functions/ask_test.dart 64:5 main.<fn>
As you can see validate method is doing exactly what is expected (throwing).
The problem seems to be that the unit test frame work is not seeing it as a match.
This is the validator which is throwing as expected.
class _AskFQDN extends AskValidator {
const _AskFQDN();
#override
String validate(String line) {
final finalLine = line.trim().toLowerCase();
if (!isFQDN(finalLine)) {
throw AskValidatorException(red('Invalid FQDN.'));
}
return finalLine;
}
}
I'm using test 1.17.5 on Dart 2.13.
The code is from the DCli package which you can find here:
https://github.com/bsutton/dcli
The specific unit test is here
https://github.com/bsutton/dcli/blob/master/test/src/functions/ask_test.dart
I am not sure this will solve your problem, but you can make your assertion a bit cleaner if you do it like this:
expect(
() => validator.validate('abc'),
throwsA(isA<AskValidatorException>().having((e) =>
e.message == 'Invalid FQDN.')));
So I have two values on a page that I need to compare and as per the result perform some actions.
//First Block
cy.get('selctor1').invoke('text').then(somevalue => {
cy.get('selector2').should('have.text', somevalue).then(() => {
#Do Something when equal
})
})
//Second Block
cy.get('selctor1').invoke('text').then(somevalue => {
cy.get('selector2').should('not.have.text', somevalue).then(() => {
#Do Something when not equal
})
})
So for the positive case when both values are equal everything works fine. But for the case when two values are not equal, it's only checking the first block and fails. What should I do so that it executes the second block when values are not equal and not the first block?
Sorry for not being clear the first time. Here is my edited answer:
Then vs Should:
Try to avoid then where possible. then is not repeatable and will introduce unexpected behaviour.
But also will should introduce unexpeced behaviour.
Example for a bad usage of then:
describe("asd", () => {
it("fails but retries", () =>{
console.log("######### first test")
cy.wrap({ fn: () => console.log(new Date())})
.invoke("fn")
.should(r => expect(r).to.eq(true));
})
it("fails but retries not", () =>{
console.log("######### next test")
cy.wrap({ fn: () => console.log(new Date())})
.invoke("fn")
.then(r => {
expect(r).to.eq(true)
});
})
})
In this example you see the same code twice but the first block uses should while the second block uses then. The assertion must fail but in the first block, the assertion is repeated. Open the DEV COnsole to see many retries for the first block but no retry in the second.
This is what I mean by "unexpected" behaviour. Let's say, you wrap a object that is dynamically extended (maybe by a UI action) and you are expecting a property on this object. In the second block (then) the UI acton must be executed very fast and before thethenis executed so that theexpect` does not fail.
In the should case, you have 4 seconds (in case of `defaultCommandTimeout is not overwritten) left until the assert will finally fail.
Bad usage of should:
describe("ad", () => {
it("test", () => {
cy.visit("https://www.cypress.io/")
cy.get("*[aria-label='pricing']")
.invoke('text').should(someValue => {
cy.get("asdad", {timeout: 5000}).should("not.exist");
})
})
})
What would you expect? A green test? No, this test fails:
Why is this the case? Because get introduces an implicit assert "should exist" (see: https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Default-Assertions ).
Should with callback skips the default assertion (see: https://docs.cypress.io/api/commands/should.html#Notes ).I think they skip it by toggling it by flag. This could have the effect of reversing the flag again and thus forces cypress to check if "asdad" does exist even though we use should not exist.
There is an issue for this stuff: https://github.com/cypress-io/cypress/issues/5963
I do not know why cy.log has the behaviour you mentioned in your case. So either you use then if you want to use cy commands within then callback or you avoid the usage of cy commands and use should with explicit assertions (expect). Maybe after that issue is fixed, cy.log also can be used.
Old Answer:
cy.get('selctor1').invoke('text').should(someValue => {
const $el = Cypress.$('selector2');
if ($el.text() ==== someValue) {
// positive
expect()....
} else {
// negative
expect()....
}
})
You can use should with a callback. This callback (and the previous invoke command) is executed as long as the timeout is reached or no assertion fails.
You always can use the raw jQuery object to work with. This depends on whether or not you need all the checks cypress is executing during a get().
Please let me know if you need further assistance.
I'm learning slowly using the wonderful Pester unit testing for Powershell for a while now. I'm kind of stuck around the usage of checking if my function can run "if not supplied any mandatory input into a function." which is giving me a red light here and wanted to achieve a green test result and move on coding.
So I have a function as follows.
function Code()
{
param(
[parameter(Mandatory=$true)]
[string]$SourceLocation)
return "Hello from $SourceLocation"
}
my test script is executed with the following checks
...
$moduleName = 'Code';
Describe $moduleName {
Context "$Function - Returns a result " {
It "does something useful with just $Function function name" {
$true | Should Be $true
}
}
Context "$Function - Returns with no input " {
It "with no input returns Mandatory value expected" {
Code | Should Throw
}
}
Context "$Function - Returns some output" {
It "with a name returns the standard phrase with that name" {
Code "Venus" | Should Be "Hello from Venus"
}
It "with a name returns something that ends with name" {
Code "Mars" | Should Match ".*Mars"
}
}
} #End Describe
my output from AppVeyor shows this outcome which the [+] are green colours and [-] is a red colour which is what I'm avoiding the best I can.
Describing Code
Context Code - Returns a result
[+] does something useful with just Code function name 16ms
Context Code - Returns with no input
[-] with no input returns Mandatory value expected 49ms
Cannot process command because of one or more missing mandatory parameters: SourceLocation.
at <ScriptBlock>, C:\projects\code\Code.Tests.ps1: line 117
117: Code | Should Throw
Context Code - Returns some output
[+] with a name returns the standard phrase with that name 23ms
[+] with a name returns something that ends with name 11ms
Any help is appreciated as I would like a green condition there as I'm not sure how to overcome certain types of message responses from Powershell and translate this into unit tests...
Per the comment from TessellatingHeckler, your code isn't working because in order to test for Throw you need to pipe the Should cmdlet a scriptblock { }:
{Code} | Should Throw
It's worth noting however that (when testing for a mandatory parameter) this works OK in AppVeyor because PowerShell is running in a non-interactive console (PowerShell.exe -noninteractive). If you try to run your Pester tests locally, your tests will seemingly be interrupted as you get prompted for input.
There's a couple of ways around this, one is to just run your tests locally using PowerShell in noninteractive mode:
PowerShell.exe -noninteractive {Invoke-Pester}
Another is to pass the parameter an explicit $null or empty value (with the caveat that you can actually have a mandatory string parameter that accepts $null and this solution won't work necessarily with all other parameter types):
It "with no input returns Mandatory value expected" {
{Code $null} | Should Throw
}
However it is worth noting that these two solutions throw different exception messages, and you should further test for an explicit message for the Throw so that your test doesn't pass if the code is failing for some other reason. E.g:
Running with -noninteractive
It "with no input returns Mandatory value expected" {
{Code} | Should Throw 'Cannot process command because of one or more missing mandatory parameters: SourceLocation.'
}
Passing it $null
It "with no input returns Mandatory value expected" {
{Code $null} | Should Throw "Cannot bind argument to parameter 'SourceLocation' because it is an empty string."
}
In summary this is only a complex issue for this specific scenario because your parameter is mandatory and you're testing for its absence.
Testing for exceptions is generally a simple process of:
{ some code } | should Throw 'message'
And works fine in both an interactive and non-interactive console.
I'm writing a play Controller that should call another web service and return its result verbatim -- same response code, same headers, same body. But it seems like the Controller is written such that I have to specify an explicit return code. I've tried getting the ahcResponse, but that doesn't seem to provide an obvious solution.
Here's what I have now:
def route(name: String, command: String) = Action {
Async {
(
WS.url("someurl").get().map {
(
response => Ok(response.body))
})
}
}
However, this always returns an "OK" status, and if it gets an error, it will pull the error HTML into the body as text.
How do I forward the results of a WS call back to my caller?
You could forward the response code and body in the following way:
WS.url(url)
.get
.map(response =>
response.status match {
// in case you want to do something special for ok
// otherwise, pattern matching is not necessary
case OK => Ok(response.body)
case x => new Status(x)(response.body)
})
.recover {
case ex: Throwable =>
InternalServerError("some exception...")
}
I'm pretty new to scala and basically I want to have a couple of functions coupled to a string in a hashmap.
However I get an error at subscribers.get(e.key)(e.EventArgs); stating Option[EventArgs => Unit] does not take parameters...
Example code:
object Monitor {
val subscribers = HashMap.empty[String, (EventArgs) => Unit ]
def trigger(e : Event){
subscribers.get(e.key)(e.EventArgs);
}
def subscribe(key: String, e: (EventArgs) => Unit) {
subscribers += key -> e;
}
}
The get method of a Map gives you an Option of the value, not the value. Thus, if the key if found in the map, you get Some(value), if not, you get None. So you need to first "unroll" that option to make sure there is actually a value of a function which you can invoke (call apply on):
def trigger(e: Event): Unit =
subscribers.get(e.key).foreach(_.apply(e.EventArgs))
or
def trigger(e: Event): Unit =
subscribers.get(e.key) match {
case Some(value) => value(e.EventArgs)
case None =>
}
There are many posts around explaining Scala's Option type. For example this one or this one.
Also note Luigi's remark about using an immutable map (the default Map) with a var instead.
Since the get method returns Option, you can use 'map' on that:
subscribers.get(e.key).map(f => f(e.EventArgs))
or even shorter:
subscribers.get(e.key) map (_(e.EventArgs))
get only takes one argument. So subscribers.get(e.key) returns an Option, and you're trying to feed (e.EventArgs) to that Option's apply method (which doesn't exist).
Also, try making the subscribers a var (or choosing a mutable collection type). At the moment you have an immutable collection and an immutable variable, so your map cannot change. A more idiomatic way to declare it would be
var subscribers = Map[String, EventArgs => Unit]()
HashMap.get() in Scala works in a bit different way, than in Java. Instead of returning value itself, get() returns Option. Option is a special type, that can have 2 values - Some(x) and None. In first case it tells "there's some value with such a key in a map". In second case it tells "nope, there's nothing (none) for this key in a map". This is done to force programmers check whether map actually has an object or not and avoid NullPointerException, which appears so frequently in Java code.
So you need something like this:
def trigger(e: Event) {
val value = subscribers.get(e.key)
value match {
case None => throw new Exception("Oops, no such subscriber...")
case Some(f) => f(e.EventArgs)
}
}
You can find more info about Option type and pattern matching in Scala here.