When running tests on stores with karma & jasmine (instead of jest), the store's state persists between tests. What's the best way to reset the state for every test?
With jest, every test is run in its own environment automatically. This post includes instructions for how to clear the require cache between tests for karma (copied below) to imitate jest, but I can't seem to get it to work.
//tests.webpack.js (suggested by linked article, modified to match my project structure)
// Create a Webpack require context so we can dynamically require our
// project's modules. Exclude test files in this context.
'use strict';
var projectContext = require.context('./path/to/js', true, /^(?!\.test).js$/);
// Extract the module ids that Webpack uses to track modules.
var projectModuleIds = projectContext.keys().map(function (module) {
return String(projectContext.resolve(module));
});
beforeEach(function () {
// Remove our modules from the require cache before each test case.
projectModuleIds.forEach(function (id) {
return delete require.cache[id];
});
});
My current file:
tests.webpack.js (current)
var context = require.context('./path/to/js', true, /\.test\.js$/);
context.keys().forEach(context);
Not sure if it helps, but here's a simplified version of the code from my tests that shows the store's state persisting between tests.
MissionStore.test.js
describe('MissionStore', function() {
beforeEach(function() {
this.MissionStore = rewire("./MissionStore");
this.registeredCallback = this.MissionStore.__get__("registeredCallback");
});
// A bunch of initialization tests without data
describe("set data", function(){
beforeEach(function(){
// Sets this.MissionStore.getMissions() to some sample data
this.registeredCallback(fetchMissions);
});
it('modifies mission data', function(){
var mission = this.MissionStore.getMissions()[0];
expect(mission.edit).not.toEqual(true);
// modify mission to add an edit flag = true
this.registeredCallback({
actionType: MissionConstants.MISSION_TOGGLE_EDIT_FLAG,
mission : mission
});
expect(this.MissionStore.getMissions()[0].edit).toEqual(true);
});
it('do something else', function(){
expect(this.MissionStore.getMissions()[0].edit).not.toEqual(true); // Failing test
console.log(this.MissionStore.getMissions()[0]);
// prints {..., edit: true}
});
});
});
In the 'do something else' test, I'm expecting the this.MissionStore state to be reset between tests so edit won't be equal to true anymore. How would I go about doing this?
Your /^(?!\.test).js$/ RegExp supposed to match every file ending with .js but not with .test.js is wrong, it will only ever match .js. It should be /^(?!.*\.test\.js$).*\.js$/. See Negative lookahead Regular Expression.
So my guess is that projectModuleIds is empty, and that you are not invalidating anything between require calls.
Related
Like in JUnit we have category annotation where we define regression, sanity name and set this category in pom.xml file to run only those Testcases. We dont need to change anything afterwards.
can we do same in Jasmine Protractor???
If we do have one file which is firstfile.ts
describe('angular-material paginator component page', () => {
const EC = protractor.ExpectedConditions;
beforeAll(async() => {
await browser.get('https://material.angular.io/components/paginator/examples');
});
it('Should navigate to next page', async() => {
await $('button[aria-label=\'Next page\']').click();
});
it('Should navigate to previous page', async() => {
await $('button[aria-label=\'Previous page\']').click();
});
it('Should change list length to 5 items per page', async() => {
await $('mat-select>div').click();
});
});
like this we have one more spec file and i want to set categories of the it block so i can write that only one word and run the test like in JUnit.
other than the option of f and x before describe and it block.
For annotation based execution you can try BDD in protractor with cucumber.
Here you can create features which can be organised and executed.
Refer this github repo : https://github.com/igniteram/protractor-cucumber-typescript.git
Please try to clone this repo and understand how it works.
This is my protractor test:
it("should check email validity", function(){
var resetButton = element(by.id('reset-button'));
element(by.model('Contact.email')).sendKeys('nick');
element.all(by.css('.form-control-error')).each(function (elem, index) {
if (index===1) {
expect(elem.isPresent()).toBe(true);
element(by.model('Contact.email')).sendKeys('#gmail.com').then(
function(){
expect(elem.isPresent()).toBe(false);
}
)
}
});
});
Behind that code there is a form with some input texts. The second one includes the email.form-control-erroris an error message which appears whenever the email format is not correct. The first time expect(elem.isPresent()).toBe(true);passes the test, the second time it does not, even if the error message disappears from the UI. It seems that Protractor does not perceive the fast change; however, it should because it is inside a promise. Do you have any explanation for that?
You should make things more reliable by adding a wait for the element to become not present ("stale") after sending the keys:
element(by.model('Contact.email')).sendKeys('#gmail.com');
var EC = protractor.ExpectedConditions;
browser.wait(EC.stalenessOf(elem), 5000);
expect(elem.isPresent()).toBe(false);
I am using React for render and Jest/Jasmine for test. I have test written using old Jest/Jasmine waitsFor and runs but these are gone now in Jasmine 2 and I am not sure how to replace with new done asyncs.
In my code React renders a small page about a user. That page has an AJAX call to fetch user posts. I want to test that user posts have come back nice, and waitsFor was very, very good at this: wait until user has some post, then continue.
I looked online at lots of people talking about using AJAX calls inside Jest test which is not what I want. My Jest test has no idea about AJAX call being made, so I need a way to wait until results come back.
Here is my current code with waitsFor and runs:
it('loads user post', () => {
var page = TestUtils.renderIntoDocument(
<UserPage params={{user: 'fizzbuzz', 'pass': 'xxx'}} />
);
waitsFor(() => {
return page.state.posts.length > 0;
}, "post loaded", 10000);
runs(() => {
var posts = TestUtils.scryRenderedDOMComponentsWithClass(page, 'post');
expect(posts.length).toEqual(10);
});
});
How can I delete the waitsFor and runs and replace with Jasmine 2.0 code that works? All Jest test knows is that page.state.posts.length must be greater than 0 before expecting anything.
You should refactor this test into two unit tests that will provide a more rigorous testing of your code. It would make the tests more independent of one another and help identify errors in a more refined scope. These won't be exact as I do not know what your code is like, but here's something along the lines I would expect to see: -
it('generates the expected properties for a page', function () {
var page = TestUtils.renderIntoDocument(
<UserPage params={{user: 'fizzbuzz', 'pass': 'xxx'}} />
);
expect(page.someProperty).toBeDefined();
expect(page.user).toEqual('fizzbuzz');
});
it('generates the correct number of posts from a given page object', function () {
var fakePage = {
// put your fake mock data here that TestUtils expects
};
var posts = TestUtils.scryRenderedDOMComponentsWithClass(fakePage, 'post');
expect(posts.length).toEqual(10);
});
I am not too sure what is happening in your renderIntoDocument function so the top test may be a little broken... It looks like there is either too much going on inside the function, or you need to test the calls that function is making instead. If you elaborate on what it does I'll edit the answer.
I have written multiple spec files for unit testing various modules on the webpage. If i run them individually, one at a time they work fine. But when i try to run all the files in a sequence, only the first file in the spec folder works while all other tests fail. Any help would be appreciated.
Every spec file loads a static page using requirejs and renders them on the page. Once the page is rendered i check whether the title, text etc is proper or not. The spec files looks like this.
AboutSpec.js-->
require(["views/About", "nls/messages"], function (About, messages) {
beforeEach(function(){
var temp = new About();
temp.render();
});
describe("Test for About Page", function () {
it("Check For About Title", function () {
var aboutTitleText = $('.eight.columns h2').text();
expect(aboutTitleText).toEqual(messages["about_title"]);
});
});
});
FooterSpec.js-->
require(["views/Footer", "nls/messages"], function (Footer, messages) {
beforeEach(function(){
var temp = new Footer();
temp.render();
});
describe("Test for Footer Page", function () {
it("Check For Footer Content", function () {
var footerText = $('.five.columns h2').text();
expect(footerText).toEqual(messages["footer_content"]);
});
});
});
jstestDriver.conf-->
load:
- jasmine/lib/jasmine-1.3.1/jasmine.js
- jasmine/lib/adapter/JasmineAdapter.js
- js-src/javaScript/require.js
- js-src/javaScript/default.js
test:
- js-test/AboutSpec.js
- js-test/FooterSpec.js
When i run this setup, the About page does not render. Only the Footer page renders due to which all the test cases of about page fails.
We're facing the exact same problem, and I've spent--how many hours, now? Oh yeah, too many!-- trying to solve this problem.
Today I discovered Karma, a JsTD replacement from Google which runs every test in a fresh iframe. It also integrates with Jenkins. I'm in the process of installing it now and will report back on how it went.
I'm starting to write Qunit tests for my existing jQuery plugins. I've gotten through a half dozen configuration style tests just to make sure everything is wired up properly. Now I'm starting to test functionality. My plugin is a countdown style plugin for textarea fields. Here's the actual working version:
http://andymatthews.net/code/textCounter/
I'm writing a test that checks that the count displayed under the field is the correct value. For example, if a field allows 100 characters and 20 characters are in the field when the page loads, the label under the field should read 80.
Here's whats in qunit-fixture:
<div id="qunit-fixture">
<textarea id="myTextarea">Existing content</textarea>
<span id="theCounter"></span>
</div>
Here's the pertinent failing test
test('setup', function(){
console.log($('#theCounter'));
equal($('#theCounter').text(), 124, 'count correctly initialized');
});
And here's the existing contents of the plugin. There is more to it, but I'm only adding more code as existing tests pass muster.
(function($) {
$.fn.textCounter = function(o){
o = $.extend( {}, $.fn.textCounter.defaults, o );
return this.each(function(i, el){
var $e = $(el),
$target = $(o.target);
// predefined count minus existing content
$e.html(o.count - $target.text().length);
console.log( $e.html() );
});
}
$.fn.textCounter.defaults = {
count: 140,
alertAt: 20,
warnAt: 0,
target: '#myTextarea',
stopAtLimit: false
}
}(jQuery));
I'm assuming that since I'm not explicitly configuring the plugin on the test harness page that the plugin using the defaults. If that's the case then the counter should start with max of 140 characters minus the 16 characters already in the field and should display 124.
Here's the problem...when a sample HTML page runs, it correctly displays 124. When the test runs, it returns $('#theCounter').text() as an empty string. Viewing the console after running the sample page AND the test, the log statement above shows 124. But the unit test shows an empty string.
This isn't anything secret so I can provide all of the files if it helps. I'm sure it's probably some sort of scope problem but I'm not experienced enough with QUnit to know what's wrong.
I don't see any code calling your plugin. You might try the following...
test( "setup", function() {
equal(
$( "#theCounter" ).textCounter().text(),
124,
"Count correctly initialized"
);
});
or you can create a module and do that in the setup phase
var textCounter;
module( "Setup", {
setup: function() {
textCounter = $( "#theCounter" ).textCounter();
},
teardown: function() {
}
});
test( "setup", function() {
equal( textCounter.text(), 124, "Count correctly initialized" );
});
It is important to know that whatever markup is in qunit-fixture will be reset for each test.