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

Freegle / iznik-nuxt3 / c116036c-55fb-4d4e-a732-06fbe0906fc1

13 Oct 2025 12:31PM UTC coverage: 34.681% (-11.0%) from 45.694%
c116036c-55fb-4d4e-a732-06fbe0906fc1

push

circleci

edwh
Migrate logo API call from v1 to v2

1053 of 3928 branches covered (26.81%)

Branch coverage included in aggregate %.

0 of 1 new or added line in 1 file covered. (0.0%)

723 existing lines in 55 files now uncovered.

2722 of 6957 relevant lines covered (39.13%)

38.05 hits per line

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

71.43
/components/InfiniteLoading.vue
1
<template>
2
  <client-only>
3
    <div
4
      :key="bump"
5
      v-observe-visibility="{
6
        callback: visibilityChanged,
7
        options: {
8
          rootMargin: '0px 0px ' + distance + 'px 0px',
9
        },
10
      }"
11
      class="infinite-loader pb-4"
12
    >
13
      <slot v-if="state == 'loading'" name="spinner"></slot>
14
      <slot v-if="state == 'complete'" name="complete"></slot>
15
      <slot v-if="state == 'error'" name="error"></slot>
16
    </div>
17
  </client-only>
18
</template>
19
<script setup>
20
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
21

22
// Derived from https://github.com/oumoussa98/vue3-infinite-loading.  Reworked radically to allow an async event
23
// handler, and to make consistent with the rest of this codebase.
24
const props = defineProps({
3✔
25
  top: { type: Boolean, required: false },
26
  target: { type: [String, Boolean], required: false, default: null },
27
  distance: { type: Number, required: false, default: 0 },
28
  identifier: { type: [String, Number], required: false, default: null },
29
  firstload: { type: Boolean, required: false, default: true },
30
  slots: { type: Object, required: false, default: null },
31
})
32

33
const emit = defineEmits(['infinite'])
3✔
34

35
const state = ref('ready')
3✔
36
const bump = ref(0)
3✔
37
const visible = ref(false)
3✔
38
let timer = null
3✔
39

40
// Methods
41
function visibilityChanged(isVisible) {
6✔
42
  visible.value = isVisible
6✔
43
}
44

45
function loading() {
103✔
46
  state.value = 'loading'
103✔
47
}
48

49
function loaded() {
103✔
50
  state.value = 'loaded'
103✔
51
}
52

UNCOV
53
function complete() {
×
UNCOV
54
  state.value = 'complete'
×
55
}
56

57
function error() {
×
58
  state.value = 'error'
×
59
}
60

UNCOV
61
function stopObserver() {
×
UNCOV
62
  complete()
×
63
}
64

65
async function emitInfinite() {
103✔
66
  loading()
103✔
67

68
  // Wait for the next tick otherwise if the event handlers return synchronously we may not end up triggering
69
  // the watch.
70
  await nextTick()
103✔
71
  emit('infinite', {
103✔
72
    loading,
73
    loaded,
74
    complete,
75
    error,
76
    stopObserver,
77
  })
78
}
79

80
function fallback() {
100✔
81
  timer = null
100✔
82

83
  if (visible.value && state.value === 'loaded') {
100!
84
    // We have loaded and not completed, and yet it's still visible.  We need to do some more.
85
    emitInfinite()
100✔
86
  }
87

88
  timer = setTimeout(fallback, 100)
100✔
89
}
90

3✔
91
// Watch state changes
92
watch(state, (newVal) => {
93
  // console.log('state changed', newVal)
94
  if (newVal === 'loading') {
206!
95
    // This is an internal change - nothing to do.
96
  } else if (newVal === 'complete') {
97
    // console.log('Complete, stop observer')
UNCOV
98
    stopObserver()
×
99
  } else {
100
    const parentEl = props.target || document.documentElement
103✔
101
    const prevHeight = parentEl.scrollHeight
103✔
102

103
    if (newVal === 'loaded' && props.top) {
103!
104
      // console.log('Adjust scrollTop')
105
      parentEl.scrollTop = parentEl.scrollHeight - prevHeight
×
106
    }
107
  }
108
})
109

110
// Watch identifier changes
111
watch(
3✔
112
  () => props.identifier,
113
  () => {
114
    // We've been asked to kick the component to reset it.
115
    bump.value++
×
116
    emitInfinite()
×
117
  }
118
)
119

120
// Lifecycle hooks
121
onMounted(async () => {
3✔
122
  if (props.firstload) {
3!
123
    await emitInfinite()
3✔
124
  }
125

126
  // It would be nice if we didn't need a timer and could be purely event-driven.  But there is no guarantee
127
  // that what happens in response to our emit will result in all the components being rendered, and although
128
  // Vue3 has Suspense I can't see an easy way of waiting for all renders to finish.
129
  timer = setTimeout(fallback, 100)
3✔
130
})
131

132
onBeforeUnmount(() => {
3✔
UNCOV
133
  if (timer) {
×
UNCOV
134
    clearTimeout(timer)
×
135
  }
136
})
137

3✔
138
// Expose methods to parent components
139
defineExpose({
140
  loading,
141
  loaded,
142
  complete,
143
  error,
144
  stopObserver,
145
})
146
</script>
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