Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to support tests with dynamic component registration? #522

Open
simonihmig opened this issue Sep 13, 2020 · 8 comments
Open

How to support tests with dynamic component registration? #522

simonihmig opened this issue Sep 13, 2020 · 8 comments

Comments

@simonihmig
Copy link
Collaborator

As suggested in the Addon Guides addons should run its test suite with embroider, and if possible with optimized settings (i.e. staticComponents: true).

There is one problem though, when tests dynamically register components/helpers, like this.owner.register('component:test-component', TestComponent);. This is a quite common pattern in more advanced tests, which is even present in this repo in various places (e.g. here). With optimized settings this causes a build error: Missing component or helper test-component.

Any suggestion how this could be solved?

As the dynamically registered components/helpers are present in the test module anyway, tree-shaking does not really apply. So the build-time assertions seems a bit too cautious, as AFAICT without that assertion the test should still work just fine, right?

Can we somehow declare components to be excluded from that check? Or should Embroider get smarter, in that it does not apply that check for components used in test files? Or even be super-smart by understanding what effect this.owner.register() has? 🤔

@simonihmig
Copy link
Collaborator Author

Can we somehow declare components to be excluded from that check?

Ok, we can. Just learned a bit about these package rules, which allow this:

packageRules: [
  {
    package: 'dummy',
    components: {
      '{{test-component}}': {
        safeToIgnore: true,
      },
    },
  },
],

If that's the suggested (interim?) solution for now, we should at least add some better documentation, as this was not really obvious!

@ef4
Copy link
Contributor

ef4 commented Sep 14, 2020

I think that's an OK interim solution.

This is an area where the correct solution is needed in Ember itself, not Embroider. I want you to be able to say:

test('invoke a component', async function(assert) {
  this.set('myComponent', class extends Component {});
  await render(hbs`<this.myComponent />`)
});

That doesn't work today because component definitions and component classes are different things. This necessarily needs to get fixed to make strict mode templates work, and people are already working on it.

The tracking issue for this kind of thing in embroider is #487.

@NullVoxPopuli
Copy link
Collaborator

I got dynamic components working in Ember 3.25 via:

import { hbs } from 'ember-cli-htmlbars';
import { setComponentHelper } from '@ember/object';

// ...
      const foo = setComponentTemplate(hbs`The Result: {{this.data.value}}`, Foo);
      this.setProperties({ foo });

      await render(hbs`<this.foo @left={{this.left}} @right={{this.right}} />`);

I'm going to use ember-compatibility-helpers to wrap this in my test so that my pre Ember 3.25 tests can use this.owner.register still (I'm only supporting embroider on Ember 3.25+ for this particular addon)

@esbanarango
Copy link

is there any official/suggested solution for this? 🙏

@NullVoxPopuli
Copy link
Collaborator

@esbanarango does this.setProperties({ MyComponent }) work for you? as in this comment: #522 (comment)

@esbanarango
Copy link

@NullVoxPopuli no, I have a slightly different need for this.owner.register('component:test-component', TestComponent);. I basically need to stub some properties or methods from the Component class.

Example:

// This is no longer a valid/normal Class as Embroider has made it "statically analyzable"
import MyComponent from 'my-app/components/my-component';

module('Integration | Component | my-component', function (hooks) {
  setupRenderingTest(hooks);

  test('...', async function (assert) {
    this.owner.register(
      'component:my-component',
      class extends MyComponent {
        // Propertier and methods I want to override
      }
    );

    await render(hbs`<MyComponent />`);
  });
});

When exporting: import MyComponent from 'my-app/components/my-component';, MyComponent is no longer a Class, but a different "object", so we can't not "extend" it anymore.

Error:

stack: >
    TypeError: Class extends value owner => {
          if (parsedBlock === undefined) {
            parsedBlock = JSON.parse(block);
          }
          if (ow...<omitted>... } is not a constructor or null
        at Object.eval (webpack:

@ef4
Copy link
Contributor

ef4 commented Jan 27, 2023 via email

@esbanarango
Copy link

Separated issue created: #1341

@ef4 ef4 removed the question label May 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants