Acceptance Test - Capture DOM Element During Download

Hey,

I have a button that when clicked initiates a download. Whilst the download takes place, the button’s text becomes “Downloading…”

I want to write an acceptance test that verifies this happens. However, I don’t know how to capture the text of the button at the point that the download is taking place because the download has always completed by the time my test tries to capture the button’s text.

Any suggestions?

Typically I do this sort of thing by changing:

await click('.download-button');
assert.equal(...);

to

click('.download-button');
assert.equal(...);
await settled();

If you don’t await the click it will click and then continue immediately allowing you to test intermediate states, then you can use settled or waitUntil or waitFor to get to the end of the async behavior.

1 Like

When I read the question I immediately thought “No!!! this would be a mess as an acceptance test” When I am faced with this dilemma I lean on integration tests. I will make a component responsible for this UI. Then I will mock or stub the actual download logic (which usually returns a promise) Then In an integration test I check to see if an unresolved promise makes the Downloading... text appear.

With this I know my component functions as expected and in my acceptance test all I need to do is check that the Happy path worked (did it download) while remaining confident that the loading state of the UI was well tested in an integration test which provides better facilities for that situation and is faster.

module('Integration | Component | my download button', function(hooks) {
  setupRenderingTest(hooks);

  test('it shows a loading indicator while downloading', async function(assert) {
    let foreverPendingPromise = new Promise(() => {});
    this.set('onDownloadStub', () => foreverPendingPromise);
    await render(hbs`
      <MyDownloadButton
        class="my-download-button"
        @onDownload={{action this.onDownloadStub}}
      />
    `);
    await click('.my-download-button');
    let result = find('.my-download-button').textContent.trim();
    assert.equal(result, 'Downloading...');
  });
});

I would also write an integration test for the error state and the success state using a rejected promise and a fulfilled promise (respectively).

1 Like