I want to get the passed or failed status of my test after each spec is executed:
var passed = jasmine.getEnv().currentSpec.results().passed();
if (!passed) {
browser.takeScreenshot().then(function(png) {
writeScreenShot(png, filename, path);
};
}
but jasmine.getEnv().currentSpec is returning undefined, I am using Jasmine 2.3 how can I get the currentSpec with Jasmine 2.3
It's likely that you are calling this from outside of the current spec. jasmine.getEnv().currentSpec will be null if there is no current spec, for example if it is called in afterAll or beforeAll blocks. Make sure that this code is invoked in the context of a spec.
I can't confirm that this is the problem without seeing more context, but this looks like it.
Are you using Jasmine 2.0? env.currentSpec is no longer supported with Jasmine 2.0.
Related
We have a medium sized angular app with currently about 700 unit tests.
A few weeks ago, perfectly fine tests started to break. Even stranger: running the tests twice can yield to different results, i.e. different tests may break.
In the console, we always find the error :
Uncaught TypeError: You provided 'undefined' where a stream was expected.
But the stack trace gives no hint to where the root of the error is actually located (see end of this post). The stack trace shows a connection to the mergeMap operator, but it turns out that we use this operator no where in our app and nowhere in our tests.
I stepped through all spec files and let them run on their own (with fdescribe). Every single spec file passes without errors. Running them all together leads to the described breakage.
Of course my guess was that we were facing an async problem so I took the effort to go through all the tests and wrap each one of them in an async environment. I also checked that every subscription gets unsubscribed at some point - this was the case for our app but not always for our tests.
However, the error still persists.
It's a big issue for our project. Any advice is very welcome.
Maybe somebody knows a way to locate the part of our tests that is causing the problem?
We now use jasmine 3.3.0, karma v3.1.4 and Angular 7.1.3.
We did the update of jasmine and angular a week ago because we hoped to get rid of the problem. Only one thing changed: before the update, tests didn't break at random but at a fixed number of tests (in our case, 639 Tests would cause a test to break, 638, 640, 641... etc would pass; 648 would break again). I assume it has something to do with the random seed that jasmine is now using.
Here is the full stack trace:
<!-- language: lang-none -->
Uncaught TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
at subscribeTo (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/util/subscribeTo.js:41)
at subscribeToResult (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/util/subscribeToResult.js:11)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._innerSub (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/operators/mergeMap.js:74)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/operators/mergeMap.js:68)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/operators/mergeMap.js:51)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/Subscriber.js:54)
at Observable._subscribe (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/util/subscribeToArray.js:5)
at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/Observable.js:43)
at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/Observable.js:29)
at MergeMapOperator.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapOperator.call (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm5/internal/operators/mergeMap.js:29)
at ____________________Elapsed_3_ms__At__Thu_Dec_27_2018_10_03_35_GMT_0100__Mitteleurop_ische_Normalzeit_ ()
at Object.onScheduleTask (:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:108)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask (:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:401)
at Object.onScheduleTask (:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:297)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask (:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:401)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask (:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:232)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask (:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:255)
at scheduleMacroTaskWithCurrentZone (:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:1114)
at :9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:2090
Oooof, sounds like things have turned flaky. We had a run in with random breaking of unit tests recently. Have you been updating your Angular and Karma versions consistently?
What we ran into is that the way unit tests are setup by default (by the Angular CLI) has changed, and that older tests were not running the proper async ways.
The error you are seeing does differ from what we saw, but I'm certain this is an avenue worth exploring to remove any flakiness introduced by the unit tests setup.
As taken from https://angular.io/guide/testing#calling-compilecomponents
describe('BannerComponent', () => {
let component: BannerComponent
let fixture: ComponentFixture<BannerComponent>
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BannerComponent ],
}).compileComponents(); // compile template and css
}));
beforeEach(() => {
fixture = TestBed.createComponent(BannerComponent)
component = fixture.componentInstance
fixture.detectChanges()
})
it('should create', () => {
expect(component).toBeTruthy()
})
Extra attention for the first beforeEach() which has an async() => {} in there, and a required .compileComponent().
The second beforeEach() is to define and populate the component variable within the shared context of the describe().
I hope this helps you figure out what is causing the flakiness. As the iterator issue stemming from RxJS seems to be pointing towards a test that is relying on state being set by a previous test, where it receives an input in the form of an Observable. If this Observable is set or defined later than the tests execution, you may be running into issues like the one you're describing.
It may be caused by async execution order of Jasmine test cases. In older versions of Jasmine, async execution order was set to false by default. But in recent versions of Jasmine, async execution order was set to true by default.
Primary Reasons: Variable has been overridden in other test case which has executed before this test case.
Solutions:
We need to find out why our variable is getting undefined. Put a console above statement where undefined is thrown. Reinitialize that variable using beforeEach.
Set random to false in your karma.config.js ex. https://github.com/karma-runner/karma-jasmine
Just upgraded to jasmine 2.0 rc5 from 1.3 and now all my tests that used waits() are broken because the waits() and waitsFor() function are undefined. I can't seem to find any reference to that anywhere online, is anyone aware of what is the new API to replace wait() ?
Well, the usage syntax for asynchronous calls changed.
You can easily see the differences between the two versions in its documentations:
Jasmine 1.3 Asynchronous support uses waitsFor() and run() functions.
According to Jasmine 2.0 Asynchronous support, these functions has been wiped out from the library. However, Jasmine 2.0 adds async support to the primitive beforeEach(), afterEach() and it() functions. The callback functions passed to these functions now can take an argument that indicates if the spec can or can't run.
Then, when you reach the necessary conditions to run your test (whenever your async job is complete), you simply call done(). And all the magic happens ;)
From the documentation:
describe("Asynchronous specs", function() {
var value;
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 1);
});
it("should support async execution of test preparation and expectations", function(done) {
value++;
expect(value).toBeGreaterThan(0);
done();
});
});
The it() spec above will run only after the setTimeout() call, because done() is called there. Note the it() callback takes an argument (done).
Use jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000
Please refer the below URL for Jasmine Documentation...
http://jasmine.github.io/2.0/introduction.html
Section is "Asynchronous Support" in the documentation.
I'm writing some page-object driven tests using Protractor and Astrolabe.
Jasmine is being used to implement describe/it style specs.
Adding custom matchers won't work using this.addMatchers (TypeError: Object #<Object> has no method 'toContainLowered'), so I used this guide to implement them.
It seems to be working, until I look closely at the output of my test run:
$> grunt test:func
Running "test:func" (test) task
Running "shell:protractor" (shell) task
Using the selenium server at http://localhost:4444/wd/hub
..
Finished in 6.727 seconds
2 tests, 1 assertion, 0 failures
Here is my code:
var loginPage = require('./../pages/loginPage');
describe('Login page', function () {
var ptor = loginPage.driver;
beforeEach(function () {
jasmine.Matchers.prototype.toContainLowered = function (expected) {
return this.actual.toLowerCase().indexOf(expected) > -1;
};
loginPage.go();
ptor.waitForAngular();
});
it('should display login page', function () {
expect(loginPage.currentUrl).toEqual(ptor.baseUrl);
});
it('should display an error when the username or password is incorrect', function() {
loginPage.login('bad', 'credentials');
ptor.waitForAngular();
expect(loginPage.lblError.getText()).toContainLowered('invalid username and/or password');
// expect(loginPage.lblError.getText()).toContain('Invalid Username and/or Password');
});
});
If I uncomment the last line and remove the toContainLowered matcher, I get the proper output:
2 tests, 2 assertions, 0 failures
I'm having a really difficult time debugging this promise-based code, and any efforts to put a console.log(this.actual.toLowerCase().indexOf(expected) > -1); will print false, which is confusing.
I even tried replacing the entire function definition with just return false;. Which still does not do anything. Finally, I tried passing no argument to the matcher, which should have thrown an Invalid Argument Error or something.
How do I define my own matchers in Jasmine when using Protractor/Astrolabe tests?
I've had similar problems with matchers, in particular with the .not matchers, which all seem to not work. I hypothesise that protractor is extending the Jasmine matchers to deal with the promises, and that that extension hasn't been applied to the .not, or to the custom matchers.
In my case, I wanted a .not.toMatch, and so I just wrote a convoluted regex that gave me what I wanted, with the not embedded in the regex.
I note that your matcher is called "toContainLowered", so perhaps you're looking for lowercase, and therefore you could instead do this with a regex by using .toMatch?
The issue I raised on this on the protractor github is here: https://github.com/angular/protractor/issues/266
I also see, in this code file: https://github.com/angular/protractor/blob/master/jasminewd/spec/adapterSpec.js, that the last commit is marked as "patched matcher should understand not". That might either fix the custom matchers for you, or provide an indication of what needs to be done to fix that custom matcher.
EDIT: now looking further into that issue thread, I see you've already been there. Which makes my answer somewhat superfluous. :-)
I have reviewed Jasmine's documentation of the toHaveBeenCalledWith matcher in order to understand whether it's possible to pass in a regular expression for an argument, if that argument is expected to be a string. Unfortunately, this is unsupported functionality. There's also an issue open on github requesting this functionality.
I've dug a bit into the codebase, and I see how it might be possible to implement this inside the existing matcher. I think it would be more appropriate to implement it as a separate matcher though, so that the abstraction is captured individually.
In the meantime, what might be a good workaround?
After doing some digging, I've discovered that Jasmine spy objects have a calls property, which in turn has a mostRecent() function. This function also has a child property args, which returns an array of call arguments.
Thus, one may use the following sequence to perform a regexp match on call arguments, when one wants to check that the string arguments match a specific regular expression:
var mySpy = jasmine.createSpy('foo');
mySpy("bar", "baz");
expect(mySpy.calls.mostRecent().args[0]).toMatch(/bar/);
expect(mySpy.calls.mostRecent().args[1]).toMatch(/baz/);
Pretty straightforward.
As of Jasmine 2.2, you can use jasmine.stringMatching:
var mySpy = jasmine.createSpy('foo');
mySpy('bar', 'baz');
expect(mySpy).toHaveBeenCalledWith(
jasmine.stringMatching(/bar/),
jasmine.stringMatching(/baz/)
);
In Jasmine 2.0 the signature changed a bit. Here it would be:
var mySpy = jasmine.createSpy('foo');
mySpy("bar", "baz");
expect(mySpy.calls.mostRecent().args[0]).toMatch(/bar/);
expect(mySpy.calls.mostRecent().args[1]).toMatch(/baz/);
And the Documentation for Jasmine 1.3 has moved.
Alternatively, if you are spying on a method on an object:
spyOn(obj, 'method');
obj.method('bar', 'baz');
expect(obj.method.argsForCall[0][0]).toMatch(/bar/);
expect(obj.method.argsForCall[0][1]).toMatch(/baz/);
Sometimes it is more readable to write it this way:
spyOn(obj, 'method').and.callFake(function(arg1, arg2) {
expect(arg1).toMatch(/bar/);
expect(arg2).toMatch(/baz/);
});
obj.method('bar', 'baz');
expect(obj.method).toHaveBeenCalled();
It give more clear visibility of method arguments (instead of using array)
As jammon mentioned, the Jasmine 2.0 signature has changed. If you are spying on the method of an object in Jasmine 2.0, Nick's solution should be changed to use something like -
spyOn(obj, 'method');
obj.method('bar', 'baz');
expect(obj.method.calls.mostRecent().args[0]).toMatch(/bar/);
expect(obj.method.calls.mostRecent().args[1]).toMatch(/baz/);
I would like to describe specifications that should be in the code, but implementation of them would be added later. In test results I would like to see them neither passed nor failed, but "are waiting" for implementation instead.
I'm interested if it is possible to do out of the box in mocha or jasmine.
Thanks
You can declare disabled functions in both mocha and jasmine using xit (instead of it), and xdescribe (instead of describe).
If you want the tests to appear as pending, in mocha you can just leave the second parameter blank in the call to the it() function. For example:
describe('Something', function () {
it('Should be pending')
xit('Should be disabled, i.e not appear on the list')
});
Update: The behaviour for xit/xdescribe is might change in Mocha if this merge happens: https://github.com/visionmedia/mocha/pull/510
Starting with Jasmine 2.0, writing xit() instead of it() for a spec marks it as pending (as already said in a comment of the accepted answer).
Aditionally, there is a pending() function you can call anywhere inside a spec to mark it as pending:
it("can be declared by calling 'pending' in the spec body", function() {
expect(true).toBe(false);
pending();
});
See also the documentation on pending specs in Jasmine 2.0.
In mocha, you can also use skip:
describe('my module', function() {
it.skip('works', function() {
// nothing yet
});
});
You can also do describe.skip to skip whole sections.