aurelia / testing

Simplifies the testing of UI components by providing an elegant, fluent interface for arranging test setups along with a number of runtime debug/test helpers.
MIT License
40 stars 27 forks source link

Cannot use ComponentTester example from skeleton-navigation with karma-typescript #71

Closed michaelbull closed 3 years ago

michaelbull commented 7 years ago

I'm submitting a bug report

Please tell us about your environment:

Current behavior:

Components tested using the ComponentTester and StageComponent are never loaded, thus assertions on them fail.

I have recreated this issue on the karma branch of my starter-kit, located here. The example is based on the code from the skeleton-navigation repository and thus should work.

The template of the component is:

<template>
  <p id="example">Hello world</p>
</template>

The viewmodel of the component is:

export class ExampleComponent {

}

And the test is:

import { bootstrap } from 'aurelia-bootstrapper';
import { PLATFORM } from 'aurelia-pal';
import {
    ComponentTester,
    StageComponent
} from 'aurelia-testing';

describe('ExampleComponent', () => {
    let component: ComponentTester;

    beforeEach(async () => {
        component = StageComponent
            .withResources(PLATFORM.moduleName('example'))
            .inView('<example></example>');

        await component.create(bootstrap);
    });

    it('should render first name', () => {
        let element: HTMLParagraphElement = document.querySelector('#example') as HTMLParagraphElement;
        expect(element.innerText).toBe('Hello world');
    });

    afterEach(() => {
        component.dispose();
    });
});

The output of the test is a failure with the following details:

  ExampleComponent
    ✗ should render first name
        TypeError: Cannot read property 'innerText' of null
            at Object.<anonymous> (unit/example.spec.ts:21:23 <- unit/example.spec.js:60:23)

        Error: Cannot call ComponentTester.dispose() before ComponentTester.create()
            at ComponentTester.dispose (/tmp/karma-typescript-bundle-240082Ffcp1HiPslP.js:16899:13)
            at Object.<anonymous> (unit/example.spec.ts:25:18 <- unit/example.spec.js:63:19)

Expected/desired behavior:

The test described above (available in the linked repository) should pass.

Testing my own components with aurelia-testing.

michaelbull commented 7 years ago

Looking further into this issue it seems that running Karma's debugger reveals the following console error:

Uncaught (in promise) No PLATFORM.Loader is defined and there is neither a System API (ES6) or a Require API (AMD) globally available to load your app.

However, I am explicitly calling initialize from aurelia-pal-browser. Is there something more I need to do to use PAL in the browser?

BBosman commented 6 years ago

I'm having the same issue only I'm not using async/await but Promises.

Some quick debugging indicates that the Promise returned by component.create never resolves (or rejects) for whatever reason, so the then or catch code never gets executed.

dsab123 commented 6 years ago

Same issue as @BBosman although I'm not using PLATFORM.

After some digging it looks like the aurelia.start() inside component.create() never resolves.

I'm on Windows 10 with node version 6.9.2, npm version 3.10.9 and jspm version 0.16.53 .

dsab123 commented 6 years ago

it seems that for some reason the resource I'm including in withResources() is not loading, and this is causing aurelia.start() to hang. I loaded up localhost:[port defined in karma.conf.js] and saw other resources, but not the one I was using in my test. For some reason the particular resource is not loading. So this is probably not the same underlying issue.

zewa666 commented 6 years ago

The issue was tracked down to the way how karma-typescript uses their own commonjs wrapper and it Not being compatible to our loaders. Havent figured out a way to solve that

kamaleswaran commented 6 years ago

got the same issue. are there any work around for this?

ryan-smith-virteom commented 6 years ago

In my requirejs project I tracked this down to window.require being reassigned by one of my dependencies that was declaring it's own global require because define.amd was undefined. aurelia-karma.js reassigns global.define and it loses the amd property so I readded it.

var originalDefine = global.define;
global.define = function (name, deps, m) {
  if (typeof name === 'string') {
    originalDefine('/base/' + root + '/' + name, [name], function (result) { return result; });
  }

  return originalDefine(name, deps, m);
}

global.define.amd = originalDefine.amd; // added this to reset define.amd

I've created a PR to aurelia/cli to add this to the generated file. https://github.com/aurelia/cli/pull/838

Can anyone confirm if this works for them or if there is a similar problem with the system loader that needs fixed?

michaelbull commented 6 years ago

@ryan-smith-virteom I'm not using the CLI so I think that's unrelated.

jalmansa88 commented 5 years ago

Hello,

I am having this issue while testing with Jasmine & Karma.

let component: ComponentTester<CustomComponent>;

component = StageComponent
            .withResources(PLATFORM.moduleName('my/path/to/component'))
            .inView('<custom-component></custom-component>');

component.bootstra(aurelia => {
    bootstrap();
    start();
   aurelia.use.standardConfiguration().plugin(myPluging);
 });

on component.viewModel.myAtrr is always throwing WARN: '%cUnhandled rejection TypeError: Cannot read property 'myAtrr' of undefined

elitemike commented 5 years ago

I was hoping to see this issue resolved as it's what I'm hitting right now. The ONLY way I have gotten it to work for me is to call create in my beforeEach and within each spec. If i eliminate either one, I can't see the component.

I ended up making a base class for my tests, in my case this is the only component i need set up so it works for me. I can fix my code in one place instead of each spec "it"

export class TestBase {
  public static async CreateComponent(json: string | IControl[]) {
    let container = new Container();
    let customControlFactory: CustomControlFactory = container.get(CustomControlFactory);
    let viewModel = new ControlView();

    let controls = await customControlFactory.loadControls(<any>json, ViewStateMode.all, false);

    viewModel.controls = controls;
    let component = StageComponent
      .withResources("custom-controls/control-view")
      .inView("<control-view controls.bind='controls'></control-view>")
      .boundTo(viewModel);

    // This is not done in error, there is an issue with Karma
    // not resolving propertly, calling it twice seems to fix it
    await component.create(bootstrap);
    await component.create(bootstrap);

    return component;
  }
}
bigopon commented 5 years ago

If the issue was no PLATFORM.Loader was specified, should it be resolved by simply add import 'aurelia-loader-webpack' to the setup.ts?

michaelbull commented 5 years ago

@bigopon karma-typescript doesn't use webpack, but regardless the example I listed in the issue's first post shows explicit registration of aurelia-loader-default

bigopon commented 5 years ago

@michaelbull I missed that. I saw PLATFORM.moduleName and assumed you used webpack