Skip to content

Let's add fetch to the settled checks? #1275

Description

@Techn1x

I've been updating an application to be ember 4 ready, part of that involved setting jquery-integration: false - meaning all existing ember-ajax and ember-data calls have switched from ajax to fetch.

Everything works great! Except... for our tests. Basically any test that was previously doing some kind of ajax request and asserting a result now fails, due to not waiting for the request to finish before asserting.

I have some options;

A) use ember-fetch 🟥

B) use ember-test-waiters in a lot of places 🟥

  • it would be a lot of work in this app to wrap all store & ember-ajax requests, last resort

C) register fetch promises just like ajax requests with the test waiter system 🟢

  • yes please! everything should just work the same when implemented

In theory, an ember app could do something like this before the tests run...

window.fetch_original = window.fetch
window.fetch = (...args) => waitForPromise(window.fetch_original(...args))

but my setup is more complicated, because I use pretender. This is likely a common setup - pretender is used by both mirage and ember-data-factory-guy. Pretender ignores whatever window.fetch is and assigns it with the github fetch polyfill
https://github.com/pretenderjs/pretender/blob/a6d53af7d5d16c3b68670a00aa2b0706a09b6ae6/src/pretender.ts#L123-L129

So we need something a little more robust that sticks around when assigned - as a proof of concept I put the following together in my test suite, and it works well.

import { waitForPromise } from '@ember/test-waiters'
QUnit.testStart(() => {
  window.fetch_original = window.fetch // store original fetch so we can restore it later

  // keep track of whatever window.fetch has been assigned to, and always return that but wrapped in waitForPromise
  // this allows it to be set by pretender at any time, and still be registered with the test waiter system
  let fetchNow = window.fetch
  function waitForFetch(...args) {
    return waitForPromise(fetchNow(...args))
  }
  Object.defineProperty(window, 'fetch', {
    get() {
      return waitForFetch
    },
    set(value) {
      fetchNow = value
    },
  })
})

QUnit.testDone(() => {
  // End of test run, do teardown by putting original fetch back.
  Object.defineProperty(window, 'fetch', {
    value: window.fetch_original,
    writable: true,
    configurable: true,
  })
  delete window.fetch_original
})

From here though, I have no idea how to integrate this into ember-test-helpers. If someone would like to give some guidance, or wield the torch, that would be great.

Over in ember-fetch, it seems the agreed upon way forward looks is to handle this in ember-test-helpers's settled() test helper
ember-cli/ember-fetch#656 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions