Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
smackfu
Jun 7, 2004

huhu posted:

Each time a new image is passed to the Image component, I want its color value to be included in the theme which OtherComponent and BarView could import from. Would there be a best practice for achieving something like this?

If theme.js is just a non-component container for an object you are mutating, I’m not sure the sub components would re-render when you update it.

Is there a common parent to all the components that use the theme? Maybe you can put the theme as a prop on that?

smackfu fucked around with this message at 15:28 on Sep 3, 2018

Adbot
ADBOT LOVES YOU

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

huhu posted:

I've got a React project
code:
theme.js
src/
    components/
        Image.js
        OtherComponent.js
    views/
        BarView.js
Each image passed to Image.js has a body similar to:
code:
{
    src: 'foo.jpg",
    color: '#ABABAB",
}
Each time a new image is passed to the Image component, I want its color value to be included in the theme which OtherComponent and BarView could import from. Would there be a best practice for achieving something like this?

Yes. There are a few ways that would be best depending on the size of your app and the bits of it we can't see from m your post.

Way 1: Have the component that is a parent to both accept the change in its state, and pass the data that is needed down as props to the components that need it.

Way 2: If the above means passing stuff down through many, many, many components and it is making you unhappy, use the new React Context API to get the data down where it needs to be.

Way 3: if you have lots and lots and lots off application state and it needs to be sent all over to lots and lots of components that aren't easy parent child relationships, then look into a state management library like Redux or Mobx. If your app is small, you likely do not want this option.

Osmosisch
Sep 9, 2007

I shall make everyone look like me! Then when they trick each other, they will say "oh that Coyote, he is the smartest one, he can even trick the great Coyote."



Grimey Drawer

FSMC posted:

I have quite a few functions that go through the DOM, extracts bits and changes bits, so I want to test the key functionality of my code. It will be running over a variety of x/html files, some that use various standards, ignore standards and do things in completely different ways. I think my issue is there is no way I'll ever get anywhere near being able to write good mock functions to emulate these functions acting on these html files. Why can't I test the actual functions acting on a html file?

Here is an example where "nodes = document.body.getElementsByTagName(elementCases[j]);" is giving me result I wasn't expecting. I don't know how I would mock this or what a mock should output. It seems like there should be a way to tests my functions on a test html file.

I may be missing something, but in general, I would
1) separate out any direct interaction with the dom to a separate service/library, and test that using something like jsdom
2) use pure functions as much as possible so it's easy to unit test.
3) use a linter; you have a missing var in the elementCases creation and nodes creation lines. This can bite you in the rear end because without 'var' you're creating a global. In general enable strict mode.
3) Try to have your code only do one thing. I find your function relatively difficult to understand because there's a lot of stuff interweaving. The presence of the IXBRL_ELEMENTS constant seems redundant since it's only really used as an argument to getCases(), and you could preserve the required tag on the getCases output if it returns an array of objects instead of just strings.

Is it the case that nodes[k].name is equal to elementCases[j]? If so you could greatly simplify things.

In general I would advise looking into lodash for some very handy tools to manipulate/transform data and objects.

Ape Fist
Feb 23, 2007

Nowadays, you can do anything that you want; anal, oral, fisting, but you need to be wearing gloves, condoms, protection.
I want to delay the return statement in a map reduce by X time to gradually load in whats being returned. I figured I'd use lodash to do it but my attempts are coming up short, any ideas?

huhu
Feb 24, 2006

Ape Fist posted:

I want to delay the return statement in a map reduce by X time to gradually load in whats being returned. I figured I'd use lodash to do it but my attempts are coming up short, any ideas?

Add a sleep function?

(from Google)
code:
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

necrotic
Aug 2, 2005
I owe my brother big time for this!
Map to promises with delays (using setTimeout to delay) and then Promise.all to get all of the results. Something like (phone posting):

code:

Promise.all(a.map((el, i) => new Promise(resolve => {
  setTimeout(() => fetch(el).then(resolve), i * 20);
})).then(arrayOfResults => {});

necrotic
Aug 2, 2005
I owe my brother big time for this!

huhu posted:

Add a sleep function?

(from Google)
code:
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

Sleeping like that isn't a good approach almost always in JS. You're blocking anything else from running during the sleep period.

MrMoo
Sep 14, 2000

huhu posted:

Add a sleep function?

(from Google)
code:
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

A slightly less awful sleep function:
JavaScript code:
// [url]https://stackoverflow.com/questions/38213668/promise-retry-design-patterns[/url]
function wait(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
}

await wait(100);

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

huhu posted:

Add a sleep function?

(from Google)
code:
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

just to harp on this, javascript is single threaded (excepting web workers) so this will block the UI thread and any timers you have running with settimeout etc. You usually don't want to sleep like this.

the settimeout equivalent does not block the main thread and just executes a function after x amount of time - however, x is just earliest the function can fire and it's not guaranteed that it will fire at x time, and settimeout is also subject to the timer resolution of your operating system (e.g. the timer might be accurate to ~15ms instead of just 1)

also, Date().getTime() is a bad way of getting current milliseconds because at very best, it will be accurate to 1ms. performance.now() can be accurate to the microsecond, except it's not actually because browser vendors realized that returning the real time using performance.now() made machines vulnerable to fingerprinting, so the brilliant solution is that your different browser vendors will add random garbage to the timestamp returned by performance.now() to make machines less vulnerable to fingerprinting (https://developer.mozilla.org/en-US/docs/Web/API/Performance/now - to the point where I think performance.now() is less accurate than Date().getTime() on Firefox.

in conclusion the internet was a mistake.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Bruegels Fuckbooks posted:



in conclusion the internet was a mistake.

The one thing all web developers can agree on.

Fish Ladder Theory
Jun 7, 2005

huhu posted:

Add a sleep function?

(from Google)
code:
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

youre hired

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
Busy waiting (which is what that is,) and sleeping aren't the same thing, and pure busy waiting is bad concurrency practice regardless of language.

huhu
Feb 24, 2006

Joke's on you, I copied it from Stack Overflow.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Joda posted:

Busy waiting (which is what that is,) and sleeping aren't the same thing, and pure busy waiting is bad concurrency practice regardless of language.
Or even if you're not doing concurrency. Busy waiting makes people's processors get hot.
Edit: if you're going to busy-wait, at least mine a bitcoin or something with those 'idle' cycles.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

huhu posted:

Joke's on you, I copied it from Stack Overflow.

You're double hired.

Ape Fist
Feb 23, 2007

Nowadays, you can do anything that you want; anal, oral, fisting, but you need to be wearing gloves, condoms, protection.

Lumpy posted:

You're double hired.

I will match this man's offer and triple it.

Also offer you team lead position.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Ape Fist posted:

I will match this man's offer and triple it.

Also offer you team lead position.

This is why those fat cats at Ape Fist inc always get the best talent :argh:

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Obfuscation posted:

But it costs money! I really like PyCharm though, so I'll check it out.

I realize this is old, but PyCharm is a superset of webstorm...at lease on the professional version, not sure about community edition.

Obfuscation
Jan 1, 2008
Good luck to you, I know you believe in hell

Thermopyle posted:

I realize this is old, but PyCharm is a superset of webstorm...at lease on the professional version, not sure about community edition.

Community version of PyCharm doesn't do javascript, sadly.

huhu
Feb 24, 2006
We've just started using Styled-Components and want to test them within Enzyme.

So we have a function...
code:
const CourseRating = ({ rating }) => {
    if (rating) {
        return <StyledCourseRating>{`${rating}/5`}</StyledCourseRating>
    } else {
        return <StyledCourseRating>No Rating</StyledCourseRating>
    }
}
And the StyledCourseRating comes from this Styled Component:

code:
const StyledCourseRating = styled.div``
Which they eventually get returned from this:

code:
function ResultListItem(props) {
    const {
        rating,
    } = props

    return (
        <ResultListItemWrapper>
            <CourseRating rating={rating} />
        </ResultListItemWrapper>
    )
}
Our test is ugly though with the .dive().dive(). We're still new to testing so maybe we're not even writing good unit tests but I'm also concerned about having to dive twice. Any suggestions?

code:
const componentProps = { rating: 4.5 }

const component = shallow(<ResultListItem {...componentProps} />)
describe('ResultListItem Component', () => {
        expect(
            component
                .find(CourseRating)
                .dive()
                .dive()
                .text()
        ).to.equal(`${componentProps.rating}/5`)
    })

FSMC
Apr 27, 2003
I love to live this lie

Osmosisch posted:

I may be missing something, but in general, I would
1) separate out any direct interaction with the dom to a separate service/library, and test that using something like jsdom
This is what I'm struggling to do. I've spent at least an hour a day for the last week trying to get somewhere but I'm just going round in circles. Either I find a comment that says don't do any DOM testing or it's easy just use jest, jasmine, jsdom, jquery, etc. I haven't found a single example I can use. I've tried following various examples but then they will be missing the main bits I need help with, e.g. it'll say "now you just write the tests like normal".

Lets use a really simple example. Say I want to test the following function on say google.com to see if it returns "google". I'm using vscode, I've used npm to install jsdom and jasmine and written a function. Now what?

code:
function getDocumentTitle(){
return document.head.getElementsByTagName("title")[0].innerText;
}

Osmosisch posted:

2) use pure functions as much as possible so it's easy to unit test.
3) use a linter; you have a missing var in the elementCases creation and nodes creation lines. This can bite you in the rear end because without 'var' you're creating a global. In general enable strict mode.
Thanks, I looked up pure functions and it's useful to understand how to write functions that are easy to write tests for. I've enabled strict mode for my linter.

Osmosisch posted:


3) Try to have your code only do one thing. I find your function relatively difficult to understand because there's a lot of stuff interweaving. The presence of the IXBRL_ELEMENTS constant seems redundant since it's only really used as an argument to getCases(), and you could preserve the required tag on the getCases output if it returns an array of objects instead of just strings.
I'm a bit confused here, can you explain this in a way a noob like me would understand? I don't know what "required tag" means, or why I would return an array of object instead of strings. Yep IXBRL_ELEMENTS is a fixed array that is only used as an argument in getCases().
code:
 var IXBRL_ELEMENTS = ['ix:denominator', 'ix:exclude', 'ix:footnoteLink', 'ix:fraction', 'ix:header', 'ix:hidden', 'ix:nonFraction', 'ix:nonNumeric', 'ix:numerator', 'ix:references', 'ix:resources', 'ix:tuple'];


Osmosisch posted:

Is it the case that nodes[k].name is equal to elementCases[j]? If so you could greatly simplify things.
Well they probably shouldn't be....

Ape Fist
Feb 23, 2007

Nowadays, you can do anything that you want; anal, oral, fisting, but you need to be wearing gloves, condoms, protection.
Whats the difference between function = ( argument ) => { result } && function(argument) { result } ?

Doom Mathematic
Sep 2, 2008
A couple of things. Most importantly, arrow functions are not passed this as an "invisible" named argument. Instead it is captured by reference from the surrounding scope.

JavaScript code:
const obj = {
  id: 78,
  method1: function() {
    return this.id
  },
  method2: () => {
    return this.id
  }
}

obj.method1() // returns 78, because `this` was `obj`
obj.method2() // throws an exception, because `this` was `undefined`

Ape Fist
Feb 23, 2007

Nowadays, you can do anything that you want; anal, oral, fisting, but you need to be wearing gloves, condoms, protection.
So for method2 you'd just reference id?

Doom Mathematic
Sep 2, 2008
I think you're suggesting something like:

JavaScript code:
const obj = {
  id: 78,
  method2: () => {
    return id
  }
}

obj.method2()
? This would throw an exception because the variable id doesn't exist.

Generally you would simply not use an arrow function as a method on an object. I only did it here to demonstrate the point. In most cases it's okay to replace a regular function with an arrow function. You only have to think twice if this is involved. Or a few other things, described here with good examples.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
Generally, you want to use arrow functions when you're using them as functions to pass around, and function() functions when you're defining members or scoped standalone real functions. In the majority of cases doing this will give you the intuitive behavior rather than the confusing behavior.
Doom Mathematic gave the example where arrow functions in the wrong place gives you confusing behavior.
The example where function() functions in the wrong place gives you confusing behavior is something like:
code:
class HerpDerp {
  constructor() {
    this.glorp = "hello!";
    this.button = document.createElement('button');
    this.button.addEventListener('click', function(event) {
      alert(this.glorp);
    });
  }
}
new HerpDerp();
If I'd used an arrow function there, when you click the button a "hello!" alert will be triggered. As written, I don't know, probably an alert that says null or maybe no alert, because 'this' inside the event listener function in that case will be ... maybe the button? Not the HerpDerp anyway. Maybe there is no this and it throws an exception.

Osmosisch
Sep 9, 2007

I shall make everyone look like me! Then when they trick each other, they will say "oh that Coyote, he is the smartest one, he can even trick the great Coyote."



Grimey Drawer

FSMC posted:

This is what I'm struggling to do. I've spent at least an hour a day for the last week trying to get somewhere but I'm just going round in circles. Either I find a comment that says don't do any DOM testing or it's easy just use jest, jasmine, jsdom, jquery, etc. I haven't found a single example I can use. I've tried following various examples but then they will be missing the main bits I need help with, e.g. it'll say "now you just write the tests like normal".

Lets use a really simple example. Say I want to test the following function on say google.com to see if it returns "google". I'm using vscode, I've used npm to install jsdom and jasmine and written a function. Now what?

code:
function getDocumentTitle(){
return document.head.getElementsByTagName("title")[0].innerText;
}

In principle I would say you want to do as little direct interaction with the DOM as possible in your logic, and abstract that away. One of the shallowest versions is something like:

code:
describe('the dom service', function() {
  it('should get the title', function() {
    var mockDom = new JSDOM(`<!DOCTYPE html><head><title>Hello world</title></head>`);
    var result = DomService.getDocumentTitle(mockDom.window.document);
    expect(result).toEqual('Hello world');
  });
});
Note that I'm forced to pass the window.document into the service in order to mock it. Using dependency injection and injecting the window.document instead would let me avoid having to pass it in.

Taking a step back, I'm also kind of curious why your data model is coming from HTML in the first place. There's probably easier-to-deal-with formats.

quote:

I'm a bit confused here, can you explain this in a way a noob like me would understand? I don't know what "required tag" means, or why I would return an array of object instead of strings.
What I meant is if getCases(IXBRL_ELEMENTS[i]) returns, instead of the array of cases, an object like :
code:
{
    ixbrlElement: 'ix:denominator,
   cases: ['foo', 'bar', 'qux']
}
you no longer need to refer to the IXBRL_ELEMENTS further in the function where you're assigning the value in the elements object. See below where I assume this is the case. I've spent some time noodling with your function trying to flatten the complexity out a bit but without more knowledge of your domain it's not going to go very far. See what you think:
code:
function getIxbrlElements() {
  return IXBRL_ELEMENTS
      .map(getCases)
      .reduce(function(elements, elementCases) {
        elements[elementCases.ixbrlElement] = elementCases.cases.reduce(getNodes, {});
        return elements;
      }, {});
}

function getNodes(value, elementCase) {
  var nodes = DomService.getTagElements(elementCase);
  // if using lodash this for loop can be written as
  //   _.zipObject(_.map(nodes, 'name'), nodes.map(nodeToObject));
  for (var k = 0; k < nodes.length; k++) {
    value[nodes[k].name] = nodeToObject(nodes[k]);
  }
  return value;
}
I've steered clear of getting too ES6-y so no arrow functions or consts.

Shaman Tank Spec
Dec 26, 2003

*blep*



E: loving christ. Figured it out. Turns out when you change the ports your flask-restful server listens to, you might want to actually change the ports in your ReactJS code as well.

Shaman Tank Spec fucked around with this message at 09:59 on Sep 12, 2018

Obfuscation
Jan 1, 2008
Good luck to you, I know you believe in hell
e: or that, whatever, glhf

huhu
Feb 24, 2006

Der Shovel posted:

E: loving christ. Figured it out. Turns out when you change the ports your flask-restful server listens to, you might want to actually change the ports in your ReactJS code as well.
Sounds like there's a few takeaways that could help you avoid this in the future. A way of debugging in code is to split the execution of your code in half and check that the values there are what you expect then whichever half isn't working as expected, split that in half.

UI/API is a pretty good split. I'd suggest two things, first learn about the network tab in Chrome developer tools. Second, get something like Postman. It can make requests so you can test the backend and you can also start up a mock backend to test your frontend is behaving correctly when you give it data you expect from your mock backend.

FSMC
Apr 27, 2003
I love to live this lie

Osmosisch posted:

In principle I would say you want to do as little direct interaction with the DOM as possible in your logic, and abstract that away. One of the shallowest versions is something like:

code:
describe('the dom service', function() {
  it('should get the title', function() {
    var mockDom = new JSDOM(`<!DOCTYPE html><head><title>Hello world</title></head>`);
    var result = DomService.getDocumentTitle(mockDom.window.document);
    expect(result).toEqual('Hello world');
  });
});
Note that I'm forced to pass the window.document into the service in order to mock it. Using dependency injection and injecting the window.document instead would let me avoid having to pass it in.

Taking a step back, I'm also kind of curious why your data model is coming from HTML in the first place. There's probably easier-to-deal-with formats.

Thanks. I managed to get jsdom working both with with a mock and then also got it working with a site by adding some code from https://github.com/dnajs/load-web-page-jsdom-jasmine. I had some trouble with jsdom at first sine it doesn't seem to support any of the dom manipulation functions I use.

There are two use cases why want good html coverage and why data is in the html in the first place. The first is sets of accounts in ixbrl format stored as xhtml, so I need to test anything built over a variety of accounts created using various software. The second is I'm working on an extension that does it's magic by getting and adding data to different sites I have no control over, if I fix something on one site I want tests to make sure I haven't broken it on another site, etc.
JSDOM seems a bit limited so I'm trying to get Karma to work.

One area I'm still a bit lost with is how to properly export functions for the spec function. I've been adding "exports.function=function;" to export each function and then using require to import them into the test file. It's really clunky. With the jasmine standalone I didn't have to do that and I just run the specrunner.html which had the location of the files and it worked fine. Is there a way to set up the command-line tests to work like that? I thought that jasmine.config would just have an option where you add your src files, but I can't find anything.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
Is there a typescript+webpack solution for debug logging that gets completely elided from final distributed code?

I want to log to the console while I'm developing, because I have a fairly complicated websocket thing going on that I'd like to easily see what communication is happening, but in a release version I'd like that logging code not just uncalled but removed.

I found libraries but they don't seem to do elision. I found you can get uglify to elide useless code, define DEBUG, and then do DEBUG && console.log(...) every time, but that seems verbose.

I found grunt-strip, that does what I want with grunt and js, but I don't know how I'd apply that in webpack+ts.

I found webpack-strip-debug, which again seems to be applying to js not ts, maybe it could be chained after the ts compile step?

Not even edit, answered my own question, but sharing because someone else might be interested:
code:
yarn add --dev strip-loader
And in webpack.config.js (where clientConfig is one of my exported config objects, and -d is used for my debug build):
code:
if (!process.argv.includes('-d')) {
    console.log('Removing debug');
    clientConfig.module.rules.unshift({
        test: /\.ts$/,
        loader: WebpackStripLoader.loader('debug'),
    });
}
And then I added a module debug
code:
export function debug(...a: any[]) {console.log(...a);}
Then I can just do debug("here is a message", some_value) in code, and it gets stripped from the non-debug build. I think I still leak the now-unused function debug; could probably get that elided by adding a closure compiler or uglify pass at the end.
(I could more easily just strip all console.log, by doing WebpackStripLoader.loader('console.log') instead of 'debug' but sometimes I want to leave a console.log in.)

Osmosisch
Sep 9, 2007

I shall make everyone look like me! Then when they trick each other, they will say "oh that Coyote, he is the smartest one, he can even trick the great Coyote."



Grimey Drawer

FSMC posted:

Thanks. I managed to get jsdom working both with with a mock and then also got it working with a site by adding some code from https://github.com/dnajs/load-web-page-jsdom-jasmine. I had some trouble with jsdom at first sine it doesn't seem to support any of the dom manipulation functions I use.

Mostly people run jasmine tests using Karma, which I see below you're moving towards. Karma is not a jsdom replacement, but a test runner, so you still need to load jsdom if you want to use it as your browser: https://www.npmjs.com/package/karma-jsdom-launcher . Karma does manage the part you're asking about regarding aggregating the test files to load, plus can do a whole bunch of other stuff like coverage reports.

If the DOM manipulation you use is not supported by jsdom you're probably best off using a browser, probably headless chrome since Phantomjs is no longer being worked on.

quote:

There are two use cases why want good html coverage and why data is in the html in the first place. The first is sets of accounts in ixbrl format stored as xhtml, so I need to test anything built over a variety of accounts created using various software. The second is I'm working on an extension that does it's magic by getting and adding data to different sites I have no control over, if I fix something on one site I want tests to make sure I haven't broken it on another site, etc.
So you're testing against live sites? That does complicate matters. I'd still advise for the unit tests at least to try and separate dom manipulation and actual logic as much as possible so you have only one thing to worry about (like css selectors vs loop corner cases or whatever).

Good luck.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

FSMC posted:

There are two use cases why want good html coverage and why data is in the html in the first place. The first is sets of accounts in ixbrl format stored as xhtml, so I need to test anything built over a variety of accounts created using various software. The second is I'm working on an extension that does it's magic by getting and adding data to different sites I have no control over, if I fix something on one site I want tests to make sure I haven't broken it on another site, etc.
JSDOM seems a bit limited so I'm trying to get Karma to work.

in general the point of unit tests should not be to verify the end to end functionality, the point of unit tests is verify that your code in isolation. the test you're talking about is more an end to end test or an integration test.

the problems with the end to end in this perspective are
a) End to end testing is slower than unit testing.
b) End to end testing is less reliable, as you're at the whims of the external site.
c) In your case, since you're testing stuff that's not under your control, the tests might break for reasons that aren't your fault or problem.

while you can test live dom manipulation using jasmine/karma, you're probably better off not using unit test tools for this kind of test, and using browser automation tools like selenium.

Hypnobeard
Sep 15, 2004

Obey the Beard



I'm working on some problems at exercism.io, and I'm running into an issue with the tests. My code is this:

code:
const isLeap = year => ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);

export default isLeap;
And it's being imported into the test file (the test framework is jest) as such:

code:
import { isLeap } from './leap';

describe('A leap year', () => {
  test('year not divisible by 4: common year', () => {
    expect(isLeap(2015)).toBeFalsy();
  });
// Other, similar tests elided..
});
The files are in the same directory, and I'm running the tests with just npm test in that directory.

The result is an error that seems to point to something in the syntax or the test setup:

code:
    TypeError: (0 , _leap.isLeap) is not a function

      at Object.<anonymous> (leap.spec.js:5:29)
          at new Promise (<anonymous>)
      at process._tickCallback (internal/process/next_tick.js:68:7)
I'm just starting out in Javascript/ES6, so this is confusing the heck out of me. What am I missing, either in my file or in the test spec?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Hypnobeard posted:

I'm just starting out in Javascript/ES6, so this is confusing the heck out of me. What am I missing, either in my file or in the test spec?
You've exported isLeap as default, but you've imported it by name.

You either want
code:
export const isLeap = year ...
Or
code:
import isLeap from './leap';
(maybe "import isLeap as * from", I'm not sure, I don't use default exports myself.)
Or a different syntax of export.

Hypnobeard
Sep 15, 2004

Obey the Beard



roomforthetuna posted:

You've exported isLeap as default, but you've imported it by name.

You either want
code:
export const isLeap = year ...
Or
code:
import isLeap from './leap';
(maybe "import isLeap as * from", I'm not sure, I don't use default exports myself.)
Or a different syntax of export.

Ahh.. this cleared it up. Need to do

code:
import isLeap from './leap';
Removing the braces fixed it. (ESLint was complaining if I tried to shift to export const.. without a default.)

Thank you a ton!

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Hypnobeard posted:

Removing the braces fixed it. (ESLint was complaining if I tried to shift to export const.. without a default.)
It might be exports = { isLeap }; if you want multiple exports.
So many ways of doing modules, each just different enough to be confusing. I'm using typescript now so everything is slightly different another different way.

necrotic
Aug 2, 2005
I owe my brother big time for this!
modiule.exports = {} is the old method. If you have export support you just call export with a const or function or whatever multiple times. Or as a map of things to export:

code:
// import { isLeap }
export {
  isLeap
};

Adbot
ADBOT LOVES YOU

Khorne
May 1, 2002
The export syntax is a mini-horror in itself. It came to be because they want you to only export one thing. It's why when you import you just "import thing from module" if it's the default export. Except, you need to explicitly say it's the default instead of just saying export. And if you export as default it bans you from using the other import syntax for that export.

It's baffling until you read about it and their intent. Even then, it's inexplicable why anyone thought not being able to import a default through curly braces was a good idea. Or why they thought only having a single export wouldn't make it automatically the default and then require curly braces, with no default, for modules with more than one export. Or, just always or never require curly braces on imports. Instead, we have what is there now which is unintuitive and awkward.

There are some shops that ban default so you can use the same import syntax in all cases. Some other places have "only use default unless you have a real good reason" and then do some high level collection of modules to export in one header-esque file type thing. Other places just mix and match as they see fit which is reasonable enough but leads to awkward situations where something is or isn't a default.

Generally, you can mix and match as you see fit. Once you know how it works it's not awful to work with.

code:
import this, { that, him, her } from './module.js';

Khorne fucked around with this message at 20:00 on Sep 15, 2018

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply