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

feat(stub-deps): ability to stub dependencies for ComponentTester #89

Open bigopon opened 5 years ago

bigopon commented 5 years ago

This adds ability to discard dependencies loading, per ComponentTester instance. What it does under the hood:

Supersedes #88 closes #88 closes #87 closes #20

@RomkeVdMeulen Can you try this branch and see if it works for your app? I didn't have very thorough test suit. Only accounted a few tests for:

Usage:

StageComponent
  .inView('some html')
  .ignoreDependencies('some/absolute/path/1', 'some/absolute/path/2')

Also added a static method inView for StageComponent class, it was a bit unnecessarily limited to have withResources() only, imo.

cc @fkleuver @zewa666 @EisenbergEffect

bigopon commented 5 years ago

One thing I didn't test properly was using it together with requirejs/systemjs, so if there could be some help with testing it with those loaders, it would be great cc @davismj @huochunpeng

zewa666 commented 5 years ago

I see you've updated a bunch of karma/webpack related settings. I guess they are solely affecting the test setup for the repo itself right? If I'm going to check it out with a Require.js based CLI project would I need to adjust anything specific except installing your PRs aurelia-testing branch?

bigopon commented 5 years ago

@zewa666 Yes. I decided to sync this with our setup in other plugin repos 😛

zewa666 commented 5 years ago

in src folder:

// parent-component.html
<template>
  <require from="./child-component"></require>
  Parent <child-component message.bind="'Child'"></child-component>
</template>

// parent-component.ts
export class ParentComponent {
}

// child-component.html
<template>
  ${message}
</template>

// child-component.ts
import { bindable } from "aurelia-framework";

export class ChildComponent {
  @bindable() public message = '';
}

Test:

import { bootstrap } from 'aurelia-bootstrapper';
import { StageComponent } from "aurelia-testing";

describe('sample', () => {

  it('should render without and with child', async () => {
    let component;
    let subComponent;

    // First block, ignoring Child-component
    component = await StageComponent
      .withResources("parent-component")
      .inView('<parent-component></parent-component>')
      .ignoreDependencies('child-component');

    await component.create(bootstrap);
    subComponent = component.element as HTMLElement;
    expect(subComponent.textContent!.trim()).toEqual('Parent');
    expect(subComponent.textContent!.trim()).not.toContain('Child');

    await component.dispose();

    // Second block, keeping Child-component
    component = await StageComponent
    .withResources("parent-component")
    .inView('<parent-component></parent-component>')
    // .ignoreDependencies('child-component');

    await component.create(bootstrap);
    subComponent = component.element as HTMLElement;
    expect(subComponent.textContent!.trim()).toContain('Child');

    await component.dispose();
  });
});

The first one passes, the second one doesn't. It seems like the recreation of the StageComponent still remembers that the ignoreDependencies as of before is active. Commenting out the first block makes the second part of the test pass.

zewa666 commented 5 years ago

Another sideffect is if i do this

// OLD
.withResources("parent-component")

// NEW
.withResources(["parent-component", "child-component"])

the ignoreDependencies doesn't work at all. Guess this is not intended right?

bigopon commented 5 years ago

@RomkeVdMeulen Thanks for the suggestion, they are very nice. It would be great if you could help on documentation of this feature too.

RomkeVdMeulen commented 5 years ago

Sure thing. I'll go get started.

zewa666 commented 5 years ago

@RomkeVdMeulen could you share the test you were performing with SystemJS? Wonders me why it failed with requirejs as depicted above.

RomkeVdMeulen commented 5 years ago

@bigopon Thanks for including my suggestion to make the calls cumulative, but as it stands it won't work anymore: this.stubbed is never initialized.

zewa666 commented 5 years ago

just as another side-note ... for RequireJS based projects ignoreDependencies accepts the relative path to src. So my sample as above is just .ignoreDependencies('child-component'); vs .ignoreDependencies('src/child-component');

RomkeVdMeulen commented 5 years ago

@zewa666 Our project is huge so that won't be practical, but what I'm doing is basically no different from the tests in template-dependency-stub.spec.ts.

Edit: our project uses an alias for our src dir, rather than relative paths. Maybe that influences things?

zewa666 commented 5 years ago

So attached please find a minimalistic example I've created with the latest CLI and RequireJS. Maybe you can spot the difference @RomkeVdMeulen Archive.zip

RomkeVdMeulen commented 5 years ago

@bigopon Could you take a look at @zewa666's sample code? It seems the second test, without ignored dependencies, isn't working well. I'm not sure why. Looks like the dependency is loaded, but something else is going wrong preventing the child component from rendering properly. If I dump the rendered HTML at the end of the test, it looks like this:

<parent-component class="au-target" au-target-id="4">

  Parent <child-component message.bind="'Child'" class="au-target" au-target-id="1"></child-component>
</parent-component>

From the au-target-id is seems the child-component is loaded, but not rendered properly.

EDIT: Nevermind, I seem to be on the wrong path. If you switch the two tests, you get

<parent-component class="au-target" au-target-id="4">

  Parent <child-component message.bind="'Child'" class="au-target" au-target-id="2">
  Child                                            
</child-component>
</parent-component>

when child-component should be ignored.

bigopon commented 5 years ago

@RomkeVdMeulen @zewa666 Can you help change the configuration of dependencies to be ignored to absolute path? It's what loader will resolve to eventually.

zewa666 commented 5 years ago

I'm not sure this has anything to do with the absolute path though @bigopon. It works the first time and is able to match the dependency. It's just on the second try it screws up.

RomkeVdMeulen commented 5 years ago

Nice work!

bigopon commented 5 years ago

I'm trying to add some base tests for requirejs to make sure things run smoothly. For the same setup, i didn't get any issues with Webpack.

RomkeVdMeulen commented 5 years ago

@bigopon I can't build the latest version. I'm getting this error:

node_modules/@types/node/index.d.ts(140,13): error TS2451: Cannot redeclare block-scoped variable 'require'.                                                                                                   
[5] test-requirejs/setup.ts(9,15): error TS2451: Cannot redeclare block-scoped variable 'require'.

Is the current version incomplete? Or were these errors not supposed to occur?

RomkeVdMeulen commented 5 years ago

I got the build back by replacing declare const require in test-requirejs/setup.ts with:

const req: any = require;
RomkeVdMeulen commented 5 years ago

Also: the main property in package.json had to be updated to dist/commonjs/src/aurelia-testing.js to get this to work.

Running @zewa666's sample against the latest version still doesn't work as it should: the dependencies are still ignored when the component tester is re-initialized without ignored dependencies.

bigopon commented 5 years ago

@RomkeVdMeulen I'm still trying to figure out what went wrong in requirejs setup. It's not any easier to debug than webpack. Also in requirejs things are not resolved to their absolute url like webpack, so it's another layer that needs to be accounted.

bigopon commented 5 years ago

There are a number of cache layers in combination of requirejs + default loader + templating. I have not been able to successfully work out how to invalidate cache of all layers for each test. I've reverted the latest code so that if anyone who uses webpack can easily use my branch and build it.

RomkeVdMeulen commented 4 years ago

@bigopon Is there perhaps someone we could pull in on this who is more in-depth on the caching layers? I also wonder wether this will work for Aurelia 2.

bigopon commented 4 years ago

V2 will not, if never, suffer any issue like this, that im pretty confident about. @fkleuver has done an amazing job to ensure apps are properly containerized. How is my branch going for you?

RomkeVdMeulen commented 4 years ago

Working fine with System loader.

\EDIT: And using absolute module paths (with an alias in my case). Since that seems to be an issue.