SecurityError when running Jest tests

Hi,

We are currently trying to implement jest as our test framework in our Aurelia application; however we have run into an issue that I am not able to solve.

When running tests we get error:

SecurityError: Could not parse url argument "blank" to replaceState against base URL "about:blank".

      at HistoryImpl._sharedPushAndReplaceState (node_modules/aurelia-pal-nodejs/node_modules/jsdom/lib/jsdom/living/window/History-impl.js:73:15)
      at HistoryImpl.replaceState (node_modules/aurelia-pal-nodejs/node_modules/jsdom/lib/jsdom/living/window/History-impl.js:57:10)
      at History.replaceState (node_modules/aurelia-pal-nodejs/node_modules/jsdom/lib/jsdom/living/generated/History.js:129:21)
      at BrowserHistory.Object.<anonymous>.BrowserHistory.setState (node_modules/aurelia-history-browser/src/browser-history.ts:214:14)
      at node_modules/aurelia-router/src/app-router.ts:194:22

This is my jest-preset.js:

import ā€˜aurelia-polyfills’;
import { Options } from ā€˜aurelia-loader-nodejs’;
import { globalize } from ā€˜aurelia-pal-nodejs’;
import path from ā€˜path’;
Options.relativeToDir = path.join(__dirname, ā€˜unit’);
globalize();

this is my test case that fails:

beforeEach(() => {

    component = StageComponent

        .withResources(PLATFORM.moduleName('app'))

        .inView('<app></app>');

    component.bootstrap(aurelia => {

        aurelia.use
            .standardConfiguration()
            .plugin(PLATFORM.moduleName('aurelia-dialog'))
            .feature(PLATFORM.moduleName('resources/index'))
            .plugin(PLATFORM.moduleName('aurelia-validation'))
            .plugin(PLATFORM.moduleName('aurelia-event-aggregator'))
            .plugin(PLATFORM.moduleName('aurelia-ui-virtualization'))
            .plugin(PLATFORM.moduleName('aurelia-dialog'));      
    });
});

it(ā€˜App should exist’, done => {
component.create(bootstrap).then(() => {
component.element;
expect(component).tobe;
done();
}).catch(e => {
fail(e);
done();
});
});
});

If I create a new app with the Aurelia CLI this test works fine. Anyone who has a clue what is causing this issue?

Regards,
Andreas

1 Like

A quick google based on the error msg you got led me to this fix https://github.com/oblador/loki/issues/51#issuecomment-385312871

Can you help give it a try? Basically initialize the window URL before each test to something, anything rather than the default, which is ā€˜about:blank’.

I did try this but it didn’t work either. It is just as if the testURL property in package.json is overruled somewhere.

1 Like

This line is incorrect, isn’t it? Shouldn’t it be

expect(component).toBeTruthy();
1 Like

No, tobe is correct syntax for this test as you can see here: https://jestjs.io/docs/en/expect#tobevalue

But I am considering changing from Jest to another test framework as it seems to be broken as of now.

1 Like

jest uses jsdom by default, its may be a downstream dependency incompatibility with your configuration+aurelia. You can change the environment to node in your jest configuration, see https://jestjs.io/docs/en/configuration#testenvironment-string. aurelia-cli sets this to node within package.json’s {ā€œjestā€} config.

1 Like

I have tried to set the testEnvironment to ā€˜jsdom’ but that just raises

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.

when trying to create to component. I am really, really lost and I can’t find any sort of documentation on how to use jest together with Aurelia. If there are any then I would love to read it.

1 Like

I use Jest to test my entire library Aurelia-Slickgrid but I barely have any tests with the creation of a Custom Element lifecycle. I mean most of my tests are for Services and such, which don’t require the component.bootstrap lifecycle. I looked at Aurelia I18N lib quite a few times for references as it is tested with Jest as well.

I still don’t think your tobe is valid, you’re missing an argument and the link you sent does say that as well toBe(value) but you simply wrote that line as:
expect(component).tobe;
there’s no argument at all and you’re not even calling the toBe method, I wonder how that can even work?

Another thing about JSDOM and Node, in my jest.pretest.ts I also added an import to the jsdom-global/register and also this line
(global as any).navigator = { userAgent: 'node.js' };
Perhaps you can give that a try, I don’t remember what it does exactly but if you want to see my full pretest, the link is here . I might have used the navigator because of this error which has some similarities with your error (that actually came up after googling your error)

oh if you look around my lib and tests, don’t be surprised at my folder structure, my unit tests are not in the ./test folder, I prefer to put them all in their sub-sections under a __tests__ folder which is recommended by Jest (e.g. the services unit tests are under /services/__tests__), so my Jest pretest is different compare to the I18N package, since that one as all their tests under /test

2 Likes

I’m getting a similar error to the original poster. Error message is:

  SecurityError: Could not parse url argument "blank" to replaceState against base URL 
"about:blank".

  at HistoryImpl._sharedPushAndReplaceState 
(node_modules/jsdom/lib/jsdom/living/window/History-impl.js:73:15)
  at HistoryImpl.replaceState (node_modules/jsdom/lib/jsdom/living/window/History-impl.js:57:10)
  at History.replaceState (node_modules/jsdom/lib/jsdom/living/generated/History.js:129:21)
  at BrowserHistory.setState (node_modules/aurelia-history-browser/dist/commonjs/aurelia-history- 

browser.js:263:18)
at node_modules/aurelia-router/dist/commonjs/aurelia-router.js:1824:25

For info my jest.pretest is

import 'aurelia-polyfills';
import { Options } from 'aurelia-loader-nodejs';
import { globalize } from 'aurelia-pal-nodejs';
import * as path from 'path';
Options.relativeToDir = path.join(__dirname, 'unit');
globalize();
jest.setTimeout(30000);

This is my test file (imports, filepaths etc redacted)

describe('index', () => {
let component: ComponentTester<Index>;

beforeEach(() => {
	component = StageComponent.withResources(resourcePaths).inView(`<index></index>`);

	component.bootstrap(aurelia => {
		aurelia.use.standardConfiguration();
		return null;
	});
});

it('should configure routes', async () => {
	await component.create(bootstrap);
});
});

The file I am testing:
import { autoinject } from ā€˜aurelia-framework’;
import { RouterConfiguration, Router } from ā€˜aurelia-router’;
import { PLMA_PLATFORM } from ā€˜./routes’;
import { ViewModelBase } from ā€˜logic/view-models/view-model-base’;

@autoinject
export class Index extends ViewModelBase {
private _router: Router;

configureRouter(config: RouterConfiguration, router: Router): void {
	this._router = router;		
	config.map(PLMA_PLATFORM);
}
}

And the html file component:

<template>
    <router-view name="platform"></router-view>
</template>
1 Like

Try changing your @autoinject() to manual @inject(...) to see if that makes any differences. I had issues with autoinject in plugins.

1 Like

ā€œI use Jest to test my entire library Aurelia-Slickgrid but I barely have any tests with the creation of a Custom Element lifecycle. I mean most of my tests are for Services and such, which don’t require the component.bootstrap lifecycle. I looked at Aurelia I18N lib quite a few times for references as it is tested with Jest as well.ā€

This was what I ended up doing as well, now my unit tests for controller, services and such works. I gave up on the whole creation thing. Thanks anyway, I might have overworked my test scenarios from the beginning.

1 Like

Great to see i18n being an inspiration for you guys. As an example for others reading this, over here bootstrapped component tests are performed. https://github.com/aurelia/i18n/blob/master/test/unit/t-attribute.spec.ts

2 Likes

@zewa666 I18N totally was an inspiration, you’re the reference for unit testing hehe :wink:

1 Like