While learning electron, I decided I would also like to train testing techniques in JavaScript. I have following code:
const winston = require('winston');
const AutoLaunch = require('auto-launch');
const launchFunction = (mb) => {
const autolaunch = new AutoLaunch();
autolaunch
.isEnabled()
.then((isEnabled) => {
if (isEnabled) {
return;
}
autolaunch.enable();
})
.catch((err) => {
winston.error(err);
});
};
I would like to assert if autolaunch.enabled() is properly triggered under specific condition and I have a lot of problem with writing any test that won't force me to create stub with exact copy of function from then(). There is an option that maybe something is wrong in this design of this solution - I can (and would like to) change code to make it more testable. How should I cope with that problem without compromising code testability?
I use mocha and sinon but I don't feel really attached to those tools
I would try more functional approach. Wrap closure in question in function and test it separately.
function enableWhenNeeded(autolaunch, isEnabled) {
if (isEnabled) {
return;
}
autolaunch.enable();
}
autolaunch
.isEnabled()
.then(curry(enableWhenNeeded, autolaunch))
.catch((err) => {
winston.error(err);
});
For purpose of the example, I made up function curry(), but I think there are at least thirty five JavaScript frameworks which provide one.
It is always a question is this code worth testing; if AutoLaunch is third party, why testing it?
Related
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 some (pseudo) code that looks as follows
const { search, hash } = window.location // get search / hash from url
const tokenParts = queryParams(search || hash) // create an object
const { id_token, access_token } = tokenParts // extract from object
const isSessionValid = validateSession(id_token) // check exp time etc and return true / false
if (isSessionValid) {
store('id_token', id_token)
store('access_token', access_token)
window.history.replaceState(null, null, window.location.pathname)
}
I see this pattern a lot in the codebase I am working on, call a method with a value, assign that value to a variable, pass that variable into another method and assign the result to another variable....and so on until you have required value you require to move the program execution on.
From what I have read, functions should really, do-one-thing - rather than these massive, complex beats that can be difficult to test.
My question is, in the case of the pseudo code above, how can this be refactored into a function that returns the result of another function and so on?
I think I need something like
const sessionisValid = validateSession(window.location)
validateSession = ({search, hash}) => (queryParams(search || hash))=> hasTokenExp({id_token})
But I do not understand...
If this is how function programming / composition should work
Is the best approach
If I am just over complicating things
call a method with a value, assign that value to a variable, pass that variable into another method and assign the result to another variable... and so on until you have required value you require to move the program execution on.
This is totally fine. You're building on big function from multiple small functions - exactly how you should do it in functional programming. The variables are just necessary for the wiring.
What you have shown is not a massive, complex beast, it's very clear and clean code. It's easy to test all the individual small functions on their own if you want.
And because all those functions are pure and your variables are immutable, it's really easy to refactor your code from
const { search, hash } = window.location // get search / hash from url
const { id_token, access_token } = queryParams(search || hash)
const isSessionValid = validateSession(id_token) // check exp time etc
if (isSessionValid) {
store('id_token', id_token)
store('access_token', access_token)
window.history.replaceState(null, null, window.location.pathname)
}
to
function getSession({search, hash}) {
const { id_token, access_token } = queryParams(search || hash)
return {
id_token,
access_token,
isSessionValid: validateSession(id_token)
};
}
const { id_token, access_token, isSessionValid } = getSession(window.location);
if (isSessionValid) {
store('id_token', id_token)
store('access_token', access_token)
window.history.replaceState(null, null, window.location.pathname)
}
but unless you can use getSession in multiple places or you need this layer of abstraction for code organisation, the refactoring is unnecessary.
how can this be refactored to use function composition?
It can't really. Function composition works only when the result of one function are fed into another function and nowhere else. But in your code, access_token and id_token are used in multiple places. While it is possible to express this in pointfree style, it's complicated, slow and too abstract. Variables are much easier to use here.
I see this pattern a lot in the codebase I am working on
What exactly is the pattern? Whenever you see duplicated code, you might want to abstract out the common parts. But you need to be evaluate how many common parts and how many distinct parts there are in the code blocks. While always possible, often it's not worth it.
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);
}));
my question is regarding the implementation of this snippet of javascript code into my chatbot:
smooch.conversations.sendMessage('app_5790dca8cab9a256005c0148', {
text: 'Fabric',
role: 'appMaker',
actions: [
{
type: 'postback',
text: 'fabric instructions',
payload: 'egg_fabric'
}
]
}).then(() => {
// async code
});
Here is my script.json file that corresponds to this specific postback:
"HOW CAN I REMOVE AN EGG STAIN?": "%[Fabric](postback:egg_fabric) %[Surface](postback:egg_surface)",
The reason I am asking this question is because I want to have multiple "surface" and "fabric" buttons throughout the chat but I want the answer the bot spits out to correspond to the question most recently asked. Thanks for your help!
What you're looking for can't be done this with script.json, you'll have to define your own state functions in script.js, and your own postback event handling.
In this answer there are some suggestions as to how you can do this with the smooch-bot-example project (which is what estherbot was forked from).
To give you some context, script.js is where the actual bot logic lives. The script.json you're looking at is a shortcut that was introduced with estherbot to make it easier to define keyword-based bots. When your bot runs, the JSON actually gets compiled into states as if the were defined in script.js in the first place. What you're attempting to build will require more than the static keyword --> behaviour mapping that the script.json is limited to.
Following up on Andrew's answer above:
Check the smooch-bot-example project, but maybe start by looking into the webhook implementation file for the postbacks (heroku/index.js) instead of the bot logic/flow definition file (script.js) file:
Within the heroku folder of the repo, check the index.js file. The function handlePostback(req, res) (should be around line 109) should help you get started. E.g. change it to something like this:
From:
function handlePostback(req, res) {
const postback = req.body.postbacks[0];
if (!postback || !postback.action) {
res.end();
}
createBot(req.body.appUser).say(`You said: ${postback.action.text} (payload was: ${postback.action.payload})`)
.then(() => res.end());
}
To something like:
function handlePostback(req, res) {
const postback = req.body.postbacks[0];
if (!postback || !postback.action) {
res.end();
}
const sAction = postback.action.text;
const sPayload = postback.action.payload;
switch (sAction) {
case "egg_fabric":
//something something
break;
case "egg_surface":
//something something
break;
default:
//something something
}
}
Hope that helps.
I am writing a SPA with typescript using breeze and knockout.
What I want to do is to create a launch manager, which can perform the neccessary steps required to even start the site (e.g. read configuration json, download odata metadata, initialize breeze metadata store and so on).
I've created the following to represent each step in the launch sequence:
export enum LauncherProgressStatus {
Ready,
InProgress,
Success,
Failed,
Aborted
}
export class LauncherProgressItem {
public status: KnockoutObservable<LauncherProgressStatus> = ko.observable<LauncherProgressStatus>();
public description: KnockoutObservable<String> = ko.observable<String>();
public statusText: KnockoutComputedFunctions<String> = ko.computed<String>(() => {
return LauncherProgressItem.getStatusText(this.status());
});
public start() {
this.action(this);
}
constructor(descriptionText: String,
public action: (arg: LauncherProgressItem) => Boolean) {
this.status(LauncherProgressStatus.InProgress);
this.description(descriptionText);
}
public static getStatusText(status: LauncherProgressStatus) : String {
switch (status) {
case LauncherProgressStatus.Ready:
return "Ready";
case LauncherProgressStatus.InProgress:
return "In progress";
case LauncherProgressStatus.Success:
return "Success";
case LauncherProgressStatus.Aborted:
return "Aborted";
default:
return "Failed";
}
}
}
TL;DR I create each step like this in code:
var item1 = new launcher.LauncherProgressItem("Loading configuration...", (item: LauncherProgressItem) => {
cfgMgr.setConfigurationFromFile("config.json?bust=" + (new Date()).getTime());
return true;
});
Now the problem: I want to utilize this to create a promise chain using Q. I can do this manually, i.e.
q.fcall(() => item1.action(item1))
.then(() => item2.action(item2))
.fail((r) => { console.log("Many whelps, HANDLE IT!") });
But I want to create some kind of manager object that doesnt really know how many steps is required. It will just be responsible for building an array of promises and execute them in sequence, whilst being able to detect errors (in the fail promise presumably) and abort the sequence.
The manager will have some kind of collection containing the LauncherProgressItem steps. Then I'm looking to build a chain of promises based on the content of that collection.
I've been looking at this for a while now but can't really seem to get my head around how to do this with Q. I've seen some examples etc but I don't really understand how it works.
Anyone got any suggestions on how to achieve this?
Update: I'll try to clarify what I am trying to achieve: My LauncherProgressItem wraps a lambda function and some state information which I bind to my view. This is why I am using these, but this is kind of irrelevant to what I'm actually struggling with.
So lets assume I have a class which contains an array of lambdas. This class has a method which will run all these lambas in sequence using Q, aborting on error. Exactly what I would achieve with the following code:
Q.fcall(doSomething).then(doSomethingElse).fail(reportError);
However, in this case doSomething and doSomethingElseresides in an array of functions, rather than a fixed number of steps. This is because I want it to be reusable, i.e. being able to run in multiple scenarios depending on the task at hand. So I want to avoid hard-coding the chain of functions to run.
Sorry I don't know typescript but I thought the comment thread above was not going very well, so here's the function you asked for in plain JS:
function runInSequence (functions) {
if (!functions || !functions.length) {
return;
}
var nextPromise = Q.fcall(functions[0]);
functions.slice(1).forEach(function (f) {
nextPromise = nextPromise.then(f);
});
nextPromise.fail(yourErrorHandler);
}