here is what I have for file.js
How could I mock the following and perform a unit testing:
thanks
var dataset = document.getElementById('test') ?
document.getElementById('test').dataset : {};
export const SERVICE_URL = 'http://localhost:/';
Using JEST / EZNYME for REACTJS - something along these lines: file.test.js
const mockTrue = {SERVICE_URL};
describe ( " Service URL ", () =>{
it ( ' should output ', () => {
expect(mockTrue).toBeCalled('http://localhost:xxxxxxx/');
});
Testing dataset
You won't be able to test both branches of the ternary condition with the current implementation.
This is because the value for dataset will be resolved the moment you import it. It is not possible to perform operations later on to add an element with id=test and hope that the value gets updated.
In order to get 100% coverage on this, you have to export a function instead :
export function getDataSet(){
return document.getElementById('test')
? document.getElementById('test').dataset
: {};
}
which makes this testable.
Testing SERVICE_URL
As other fellows mentioned, you can't do any better than
expect(SERVICE_URL).toBe('http://localhost:/');
Testing constant values is just testing for the sake of it. Apart for ensuring this constant doesn't get modified without an "are you sure?" flag, this doesn't bring any value whatsoever.
Some comments
Achieving 100% test coverage is an utopy that lead to the development of brittle tests. This purism is doing you disservice.
If truly you want to get to this shiny 100%, it is preferable that you remove dummy code from test coverage.
Try this, this should assert that your SERVICE_URL contains the value you expect:
describe ( " Service URL ", () =>{
it ( ' should output ', () => {
expect(SERVICE_URL).toBe('http://localhost:/');
});
});
Related
I am looking to extract a URL parameter from the current URL I'm testing with Cypress. I was able to basically get the answer from this SO post, however, my extracted values are not available to me when I use Cypress's .its() command.
The parameters in the url all have periods in them, and I believe this is the cause for my error.
Here is my custom Cypress Command I'm building:
Cypress.Commands.add('getParmsCommand', function(value) {
cy.url().as('url')
cy.then( () => {
cy.log(this.url)
const kvPairArray = this.url.toString().split('?')[1].toString().split('&')
const paramObj = {}
kvPairArray.forEach(param => {
cy.log(param)
//default 'value' to 0 if it doesn't exist
const [ key, value="0" ] = param.split('=')
paramObj[key] = value
})
//forcefully adding a debug element to the key value store for testing
paramObj['beverage'] = 'soda'
cy.wrap(paramObj)
.its('timeline.ws') //doesn't work
// .its(`${Cypress.$.escapeSelector('timeline.ws')}`) doesn't work
// .its('timeline\.ws') doesn't work
// .its('"timeline.ws"') doesn't work
// .its('beverage') this DOES work!
.then(parmVal => {
cy.log(parmVal)
})
Here is the relevant part of the URL that I'm trying to extract from:
timeline.ws=3600000&timeline.to&timeline.fm&timeline.ar=false
You can see from the error that Cypress is only looking for the id timeline, NOT timeline.ws; it completely ignores everything after the period, and thus, never finds my parameter.
I saw there was a similar error with Cypress's .get() function back in 2018.
I am new to both javascript and Cypress, so I hope it's just a weird easy thing I'm overlooking. Any advice or educated guesses are greatly welcome at this point!
Thank you.
.its() is just a shorthand for property extraction. Since it fails with the period, you could instead use bracket notation in a .then().
cy.wrap(paramObj)
.then(paramObj => paramObj['timeline.ws'])
or just
cy.wrap(paramObj['timeline.ws'])
Playing around with the URL constructor
const urlString = 'http://example.com?timeline.ws=3600000&timeline.to&timeline.fm&timeline.ar=false'
const url = new URL(urlString)
cy.wrap(url.searchParams.get('timeline.ws'))
.should('eq', '3600000')
cy.wrap(url.searchParams.get('timeline.to'))
.should('be.empty')
cy.wrap(url.searchParams.get('timeline.ar'))
.should('eq', 'false')
I've updated my cypress to 9.7.0 version and right now I have a problem with deep equal. When I wrote test line of code:
expect([1,2,3]).to.deep.equal([1,2,3]);
Everything works correctly.
While I'm testing redux store I got an error which is looks
Timed out retrying after 4000ms: expected [ Array(2) ] to deeply equal [ Array(2) ]
Arrays in devtool console preview are the same... I've tried in two ways to write test. I also combined it with async and timeouts
First try:
it('Example redux check', () => {
cy.fixture('file.json').then((fixtures) => {
cy.window()
.its('store')
.invoke('getState')
.its('queue.queueItems').should('deep.equal', fixtures.store.queue.queueItems);
});
});
Second try
it('Example redux check', () => {
cy.fixture('file.json').then((fixtures) => {
const getQueueItems = (win) => {
return win.store.getState().queue.queueItems;
}
cy.window()
.pipe(getQueueItems)
.should('deep.equal', fixtures.store.queue.queueItems);
});
});
Had anyone similar issue or idea how to avoid that timeout? Exactly the same is happening while comparing async payloads...
I couldn't fault the deep.equal assertion in Cypress v9.7.0, even deeply nested arrays and objects - except when the order differed.
If your problem is difference in array order, try adding package deepEqualInAnyOrder
const deepEqualInAnyOrder = require('deep-equal-in-any-order');
chai.use(deepEqualInAnyOrder);
it('matches when ordering is different', () => {
const expected = [{a:{x:1}}, {b:2},{c:3}];
expect([{a:{x:1}}, {b:2}, {c:3}]).to.deep.equal(expected) // passes
expect([{b:2}, {a:{x:1}}, {c:3}]).to.deep.equal(expected) // fails
expect([{b:2}, {a:{x:1}}, {c:3}]).to.deep.equalInAnyOrder(expected) // passes
});
I also wanted to see if deep.equal on the <h1> element of http://example.com would succeed.
Here is my minimal, reproducible example.
// Cypress 9.7.0
it('passes deep-equal of two DOM objects', () => {
cy.visit('http://example.com')
cy.get('h1').then($el1 => { // get h1 1st time
cy.get('h1').then($el2 => { // get another copy
// Are they different objects?
expect($el1).to.not.equal($el2) // pass
expect($el1 === $el2).to.equal(false) // pass
// Do they deep-equal
expect($el1).to.deep.equal($el2) // pass
})
})
})
Nearly all frontends I use have Cypress including some open source ones.
It is related to a few issues opened on GitHub and affects latest versions of Cypress.
https://github.com/cypress-io/cypress/issues/21353
https://github.com/cypress-io/cypress/issues/21469
This is what I get on a WIP after upgrading some tests that use deep.equal:
Your first example looks more standard.
I recommend downgrading to a lower version. The following version worked for me before upgrade:
9.5.4
I have a function that I'm including on each line of my component that looks at and filters off of the returned number of records with a specific status and then takes the length of that array and displays it on the screen.
{props.locations.filter(x => x.details && x.details.status === "NEVER").length}
Currently there are only 3 separate statuses that a location could possibly have. Because of that, I'm trying to create a separate function that looks at whatever status is passed in instead of hard coding it for each line in my component. I recognize that this might be a really basic question, but does any have any idea how to do this?
The nicest is to able to partially apply status, so lets put it as a first argument
const filter = status => locations => {
return locations.filter(x => x.details && x.details.status === status).length;
}
Now we can make nice filters for every status
const neverFilter = filter('NEVER');
const progressFilter = filter('PROGRESS')
// and use it
const results = neverFilter(locations);
If you need it can be used also in one line, so its very flexible construct
const results = filter('NEVER')(locations);
PS. I didn't append any TS types as you did not put any in your question, but if u use TS, status should be some kind of union like type Status = 'NEVER' | 'Other', and location should be kind of Record type. Just saying :)
Something like this:
filter = (locations, status) => {
return locations.filter(x => x.details && x.details.status === status).length;
}
And call the function:
this.filter(props.locations, 'NEVER');
I brought the book "rxjs in action" and just finish the testing section.
Testing rxjs codes are different then usual testing, because everything are lazy loading.
In the book, they mention two test method, either passing done(I am using QUnit and done signals async code is finish) or marble diagrams.
My question is, which method should I choose, that I have mentioned above?
I have been getting this question a lot from my colleagues. I finally got around to document my ways of testing RxJs on my blog. Since your question seems to be related to RxJs5 i will only quote the relevant part of my post here.
Testing in RxJs5 the RxJs4 way
When you migrate your codebase from RxJs4 towards 5 you will find out that a lot of things have been moved, renamed and above all that the implementation of the TestScheduler is no longer available. RxJs contributor kwonoj has created a compatibility shim to help migration towards RxJs5. You can install it using npm npm install #kwonoj/rxjs-testscheduler-compat. Not all features of the TestScheduler are implemented but the most important .startScheduler is working.
const TestScheduler = require('#kwonoj/rxjs-testscheduler-compat').TestScheduler;
const next = require('#kwonoj/rxjs-testscheduler-compat').next;
const complete = require('#kwonoj/rxjs-testscheduler-compat').complete;
it('works in RxJs5 with the compat package', () => {
const scheduler = new TestScheduler(); // Note; no longer the Rx.TestScheduler
const results = scheduler.startScheduler(
() => Rx.Observable.interval(100, scheduler).take(3),
{ created: 100, subscribed: 200, unsubscribed: 1000 } // NOTE: disposed is now renamed to unsubscribed
);
collectionAssert.assertEqual(res.messages, [
next(200 + 100, 0),
next(200 + 200, 1),
next(200 + 300, 2),
complete(200 + 300)
]);
});
Testing in RxJs5 using the new Marble testing syntax
The RxJs team has introduced marble testing syntax to more visually define how your operator or custom code should operate.
var e1 = hot('----a--^--b-------c--|');
var e2 = hot( '---d-^--e---------f-----|');
var expected = '---(be)----c-f-----|';
expectObservable(e1.merge(e2)).toBe(expected);
At the time of writing this post they have not yet made this approach really easy to use outside of the RxJs5 library itself. There are implementations available to see how to do it yourself. You can also look around in the codebase of RxJs5 to see how to setup your testing framework to do your own marble tests. There is an open issue about documenting testing with RxJs5. I have not yet succeeded to get my testing framework setup to do marble testing in this way.
Time has passed, and now it is definitely possible (even easy) to use these marble tests yourself using TestScheduler. They are a great way to comprehensively test emissions over time, errors, completions and subscriptions in an easy-to-understand format. Here is a sample from their docs:
import { TestScheduler } from 'rxjs/testing';
const testScheduler = new TestScheduler((actual, expected) => {
// asserting the two objects are equal
// e.g. using chai.
expect(actual).deep.equal(expected);
});
// This test will actually run *synchronously*
it('generate the stream correctly', () => {
testScheduler.run(helpers => {
const { cold, expectObservable, expectSubscriptions } = helpers;
const e1 = cold('-a--b--c---|');
const subs = '^----------!';
const expected = '-a-----c---|';
expectObservable(e1.pipe(throttleTime(3, testScheduler))).toBe(expected);
expectSubscriptions(e1.subscriptions).toBe(subs);
});
});
If you use Jasmine, I wrote a little helper called marbleTest() to reduce boilerplate, available in #s-libs/ng-dev:
import { marbleTest } from "s-ng-dev-utils";
it("generate the stream correctly", marbleTest(helpers => {
const { cold, expectObservable, expectSubscriptions, testScheduler } = helpers;
const e1 = cold(" -a--b--c---|");
const subs = " ^----------!";
const expected = "-a-----c---|";
expectObservable(e1.pipe(throttleTime(3, testScheduler))).toBe(expected);
expectSubscriptions(e1.subscriptions).toBe(subs);
}));
How I can set two different test messages for fail and pass test cases and after running all test cases how I can get list of all fail and pass messages which I can print in log file or xml file.
What is better way to store all messages and get in correct format.
Here is my Sample Home page.js
HomePage = function () {
var PageTestParams = TestParams.Modules.HomePage,
PageLangText = Lang.Modules.HomePage;
SearchResult = function(test){
},
SearchTextField = function(test){
test.assertExists(PageTestParams.SearchFormSelector, PageLangText.SuccessMsg["SearchForm"]);
SearchResult(test);
},
NavigationCount = function(test){
test.assertElementCount(PageTestParams.NavigationSelector, PageTestParams.NavigationCount,PageLangText.SuccessMsg["NavigationCount"]);
SearchTextField(test);
},
CheckTitle = function(test){
test.assertTitle(PageTestParams.Title, PageLangText.SuccessMsg["TitleText"]);
casper.test.pass("main fail ho gaya");
NavigationCount(test);
},
this.init = function(test){
CheckTitle(test);
}
};
I am passing this JS for test assertion if any test case fail or pass the same message is getting printed for same scenario. I have searched and got below syntax but its printing same message which I have setted in test assertion.
casper.test.on("fail", function(failure) {
casper.echo("FAIL " + failure.message);
});
To get two different messages when using a single test is something I have personally not come across yet. If you want a way to work around it you could do something like:
var x=4;
if(x>2){
casper.test.pass("PASS Message.");
}else{
casper.test.fail("FAIL Message.");
}
You could manipulate the if statement to have a boolean or whatever else you may like, but this seems like the most obvious way I would do it.
As for getting a list of all passing and failing messages, the extent I know about that is that there are the getFailures(); and a getPasses(); methods, these may or may not be what your looking for, but maybe they can help get you started! Good Luck!
You can do something like this (same logic for success or fail):-
var successes = [];
casper.test.on("success", function(success) {
successes.push(success);
});
Then on casper.run you can do a couple of things:-
1) To see the full dump of all successes (you can see all the properties) you can do this:-
casper.run(function () {
test.done();
require('utils').dump(successes);
});
2) to output the array of successes one by one (so you can format the output) you can do:-
casper.run(function () {
test.done();
successes.forEach(function(item){
casper.echo(item.standard);
});
});
3) I assume you know you can also output the full test assertions to xunit by passing in --xunit=output.xml