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

Passing arguments into components while testing. #14

lcpriest opened this Issue Sep 25, 2017 · 3 comments


None yet
3 participants
Copy link

lcpriest commented Sep 25, 2017

Hi team!

Is it possible to pass arguments into components while rendering them for testing?

  test('it renders', async function(assert) {
    this.rating = 10;

    await this.render(hbs`<feedback-form rating={{rating}} />`);

I understand that this is a contrived example as I could just pass "10" directly, but I would also like to be able to pass closure actions (not in current documentation, I found an example here).


This comment has been minimized.

Copy link

tomdale commented Oct 13, 2017

There is not a super easy API for doing this yet, although it's being worked on and is high priority once all of the recent performance-related work stabilizes.

If you have the appetite for hacking on low-level VM APIs, there is theoretically a way to do this today.

The core Glimmer "initial render loop" happens when you create a template iterator and call .next() on it until it is done. (example)

The template iterator encapsulates a few different pieces of state required to perform the render.
One of these things is the "main" or "root" template—the entry point where Glimmer starts rendering. Note that this is a very simple template only; there's no associated component. (example, glimmer.js main template)

So if there's no component, how does the template get data? If I type {{someVal}} in the root template, where does someVal come from?

Specifically for the root template, that comes from a special Reference we call "self."

In Glimmer.js apps, self is a reference that contains an array, _roots, which is a list of metadata for every component that you've rendered via renderComponent. (example)

If we combine these concepts, it should be possible to build a test helper that:

  1. Compiles a new template invoking the component under test, like <FeedbackForm @rating={{rating}} />.
  2. Creates a new self reference that wraps { rating: 10 } (or whatever args you might want to pass).
  3. Joins the compiled template and the self plus the other state/configuration in the example above into a new template iterator and renders it.

I wanted to write down how this stuff works in case someone is highly motivated to dig in themselves, but I'll be upfront that it's a non-trivial amount of work involving low-level parts of the VM. It might be a fun project, but if you're just wanting to get work done, the best answer might be to wait for the renderComponent API that can take arbitrary arguments to get finished. 😁

@tomdale tomdale added the enhancement label Oct 13, 2017

topaxi pushed a commit to topaxi/glimmer.js that referenced this issue Oct 27, 2017

@mrloop mrloop referenced this issue Dec 8, 2017


Tests?!!?!? #26


This comment has been minimized.

Copy link

rondale-sc commented Sep 28, 2018

Feature added here: glimmerjs/glimmer-test-helpers#4

Bump @glimmer/test-helpers (major update)


This comment has been minimized.

Copy link

rondale-sc commented Oct 1, 2018

Small update here:

The update in the PR I linked unregistered the main ComponentManager which we needed. glimmerjs/glimmer-test-helpers#5 Fixes that. I've confirmed in my own project that on "@glimmer/test-helpers": "0.31.1" You can write tests like this:

test('should call preloadImages on didInsertElement', async function(assert) {

  this.images = [{ retinaSource: 'foo', source: 'bar' }];
  await this.render(hbs`<PreloadImages @images={{this.images}} />`);

  // assertion occurs in a spy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment