• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Freegle / iznik-nuxt3 / 9b23a344-cf13-4269-8c28-f8ce8287ca9f

22 Oct 2025 08:33AM UTC coverage: 45.404% (-0.7%) from 46.073%
9b23a344-cf13-4269-8c28-f8ce8287ca9f

push

circleci

edwh
MT: Make sure all buttons are showing in the chat footer for smaller screens.

1760 of 4628 branches covered (38.03%)

Branch coverage included in aggregate %.

4010 of 8080 relevant lines covered (49.63%)

100.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.09
/composables/useFetchRetry.js
1
// Originally based on https://github.com/jonbern/fetch-retry, but reworked for our purposes.
2
import { useMiscStore } from '~/stores/misc'
3

4
class FetchError extends Error {
36✔
5
  constructor(message, response) {
6
    super(message)
×
7
    this.response = response
×
8
  }
9
}
10

11
export function fetchRetry(fetch) {
36✔
12
  const retryDelay = function (attempt, error, response) {
36✔
13
    // Slowly back off for longer each time.
14
    return attempt * 1000
×
15
  }
16

17
  const retryOn = async function (attempt, error, response) {
36✔
18
    // No point retrying until we know we are back online.
19
    const miscStore = useMiscStore()
1,756✔
20
    await miscStore.waitForOnline()
1,756✔
21

22
    if (attempt > 10) {
1,756!
23
      return [false, false, null, new Error('Too many retries, give up')]
×
24
    }
25

26
    if (miscStore?.unloading) {
1,756!
27
      // Don't retry if we're unloading.
28
      console.log("Unloading - don't retry")
54✔
29
      return [false, false, null, new Error('Unloading, no retry')]
54✔
30
    }
31

32
    // Some browsers don't return much info from fetch(), deliberately, and just say "Load failed".  So retry those.
33
    // https://stackoverflow.com/questions/71280168/javascript-typeerror-load-failed-error-when-calling-fetch-on-ios
34
    const blandErrors = ['load failed', 'failed to fetch']
1,701✔
35
    if (blandErrors.includes(response?.statusText.toLowerCase())) {
1,756!
36
      console.log('Load failed - retry')
×
37
      return [true, false]
×
38
    }
39

40
    // Retry on pretty much any error except those which can legitimately be returned by the API server.  These are
41
    // the low 400s.
42
    if (error !== null || response?.status > 404) {
1,756!
43
      console.log('Error - retry', error, response?.status)
×
44
      return [true, false]
×
45
    }
46

47
    if (response?.status === 200) {
1,756!
48
      try {
1,701✔
49
        const data = await response.json()
1,701✔
50

51
        if (!data) {
1,701!
52
          // We've seen 200 responses with no data, which is never valid for us, so retry.
53
          console.log('Success but no data - retry')
×
54
          return [true, false]
×
55
        } else {
56
          // 200 response with valid JSON.  This is the rule not the exception.
57
          return [false, true, data]
1,701✔
58
        }
59
      } catch (e) {
60
        // JSON parse failed.  That shouldn't happen, so retry.
61
        return [true, false]
×
62
      }
63
    } else {
64
      // Some error that we aren't supposed to retry.
65
      if (!error) {
×
66
        error = new FetchError(
×
67
          'Request failed with ' + response?.status,
×
68
          response
69
        )
70
      }
71

72
      return [false, false, null, error]
×
73
    }
74
  }
75

76
  return function (input, init) {
36✔
77
    return new Promise(function (resolve, reject) {
1,762✔
78
      const wrappedFetch = async function (attempt) {
1,762✔
79
        let response = null
1,762✔
80
        let error = null
1,762✔
81
        let doRetry = false
1,762✔
82
        let success = false
1,762✔
83
        let data = null
1,762✔
84

85
        try {
1,762✔
86
          response = await fetch(input, init)
1,762✔
87
        } catch (e) {
88
          console.log('Error in attempt', e)
48✔
89
          error = e
48✔
90
        }
91

92
        // We might retry in a variety of circumstances, including apparent success.
93
        ;[doRetry, success, data, error] = await retryOn(
1,756✔
94
          attempt,
95
          error,
96
          response
97
        )
98

99
        if (success) {
1,762✔
100
          // We have to pass the data because .json() can only be called once.
101
          resolve([response.status, data])
1,701✔
102
        } else if (doRetry) {
54!
103
          console.log('Retry')
×
104
          retry(attempt, null, response)
×
105
        } else {
106
          reject(error)
54✔
107
        }
108
      }
109

110
      function retry(attempt, error, response) {
×
111
        const delay = retryDelay(attempt, error, response)
×
112

113
        setTimeout(function () {
×
114
          wrappedFetch(++attempt)
×
115
        }, delay)
116
      }
117

118
      wrappedFetch(0)
1,762✔
119
    })
120
  }
121
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc