spierepf
spierepf

Reputation: 2916

What is the correct way to include one js file in another?

The following JavaScript code works:

let Color = require('color');

class Example {
    its_not_easy_being_green() {
        return Color('green');
    }
}

test('It is not easy being green', () => {
    expect(new Example().its_not_easy_being_green()).toBeDefined();
})

and npx jest gets me a greenbar.

$ npx jest
 PASS  test/example.spec.js
  ✓ It is not easy being green (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.351 s, estimated 1 s
Ran all test suites.

However, any time I try to separate the class from the test I get various errors:

The most common is one about not being permitted to use import outside a module.

Or that Example is not a constructor.

What I am trying to do is move everything that isn't the three line test out of the JavaScript file that I've posted above.

If this were Java, I'd move that stuff into a separate .java file and then import that file in my test.

If this were C there would be a linker and #include involved.

What I've tried is to create an Example.js file:

let Color = require('color');

class Example {
    its_not_easy_being_green() {
        return Color('green');
    }
}

and then require it in the test:

let Example = require('Example.js')

test('It is not easy being green', () => {
    expect(new Example().its_not_easy_being_green()).toBeDefined();
})

But that gets me a complaint about Example not being a constructor, which, I suppose is true. It is a class, which presumably has a pretty inert default constructor of some kind.

I've also tried replacing the require with an import:

import('Example.js')

test('It is not easy being green', () => {
    expect(new Example().its_not_easy_being_green()).toBeDefined();
})

But that gets complaints about not being permitted to use import outside a module.

Is it possible to separate the jest test from the code being tested in JavaScript?

Upvotes: 0

Views: 880

Answers (1)

jfriend00
jfriend00

Reputation: 707148

There is no #include in Javascript - it uses a module system instead where you export things you want to share.

It is best to learn the tools the language offers rather than trying to force it to do something the way a different language does things.

Also, note there are two types of modules in nodejs, CommonJS modules that use require() and module.exports and ESM modules that use import and export. Your project appears to be set up for CommonJS so that's what you would use unless you want to configure the project to be an ESM module project and then use the ESM rules for importing and exporting.

For a CommonJS project:

const Color = require('color');

class Example {
    its_not_easy_being_green() {
        return Color('green');
    }
}

module.exports.Example = Example;

Then, in your main file:

const { Example } = require('./Example.js')

test('It is not easy being green', () => {
    expect(new Example().its_not_easy_being_green()).toBeDefined();
});

FYI, require(someModule) gets you whatever module.exports was. If you assign something directly to module.exports such as:

// in color.js

module.exports = function Color() {
     // do something here
}

Then, you would use that like this:

const Color = require('color');

But, if you just add a property to the module.exports object such as this:

// in Example.js
const Color = require('color');

class Example {
    its_not_easy_being_green() {
        return Color('green');
    }
}

module.exports.Example = Example;

Then you must get the .Example property off the exported object in any of these ways:

const { Example } = require('./Example.js');

const Example = require('./Example.js').Example;

const exampleExports = require('./Example.js');
const Example = exampleExports.Example;

Note, the brackets in the syntax:

const { Example } = require('./Example.js');

is called "object destructuring" and is a shortcut syntax.

The color.js method above is done when there's only one main export from the module so rather than exporting an object, you export the function directly.

The example.js method above is done when you have more than one main export from the module (or you want to retain the flexibility to have more than one top-level export in the future) like this:

// in Example.js
const Color = require('color');

class Example {
    its_not_easy_being_green() {
        return Color('green');
    }
}

class SubExample extends Example {
    its_not_easy_being_red() {
        return Color('red');
    }
} 

// multiple exports
module.exports.Example = Example;
module.exports.SubExample = SubExample;

Upvotes: 1

Related Questions