Quellcode durchsuchen

CodeRabbit Generated Unit Tests: Add unit tests

coderabbitai[bot] vor 1 Monat
Ursprung
Commit
7f73e31d42

+ 269 - 0
packages-private/benchmark/client/__tests__/data.spec.ts

@@ -0,0 +1,269 @@
+import { describe, it, expect, beforeEach } from 'vitest'
+import { buildData } from '../data'
+import { isRef } from 'vue'
+
+describe('benchmark/data', () => {
+  describe('buildData', () => {
+    it('should generate default 1000 rows when no count is provided', () => {
+      const data = buildData()
+      expect(data).toHaveLength(1000)
+    })
+
+    it('should generate the specified number of rows', () => {
+      const data = buildData(100)
+      expect(data).toHaveLength(100)
+    })
+
+    it('should generate more than 1000 rows when requested', () => {
+      const data = buildData(5000)
+      expect(data).toHaveLength(5000)
+    })
+
+    it('should generate zero rows when count is 0', () => {
+      const data = buildData(0)
+      expect(data).toHaveLength(0)
+    })
+
+    it('should generate rows with unique incrementing IDs', () => {
+      const data = buildData(100)
+      const ids = data.map(row => row.id)
+      const uniqueIds = new Set(ids)
+
+      expect(uniqueIds.size).toBe(100)
+
+      // Check IDs are incrementing
+      for (let i = 1; i < ids.length; i++) {
+        expect(ids[i]).toBeGreaterThan(ids[i - 1])
+      }
+    })
+
+    it('should generate rows with label as shallowRef', () => {
+      const data = buildData(10)
+
+      for (const row of data) {
+        expect(isRef(row.label)).toBe(true)
+        expect(typeof row.label.value).toBe('string')
+      }
+    })
+
+    it('should generate labels with three words (adjective color noun)', () => {
+      const data = buildData(50)
+
+      for (const row of data) {
+        const label = row.label.value
+        const words = label.split(' ')
+        expect(words).toHaveLength(3)
+        expect(words[0]).toBeTruthy() // adjective
+        expect(words[1]).toBeTruthy() // color
+        expect(words[2]).toBeTruthy() // noun
+      }
+    })
+
+    it('should generate labels from predefined word lists', () => {
+      const adjectives = [
+        'pretty',
+        'large',
+        'big',
+        'small',
+        'tall',
+        'short',
+        'long',
+        'handsome',
+        'plain',
+        'quaint',
+        'clean',
+        'elegant',
+        'easy',
+        'angry',
+        'crazy',
+        'helpful',
+        'mushy',
+        'odd',
+        'unsightly',
+        'adorable',
+        'important',
+        'inexpensive',
+        'cheap',
+        'expensive',
+        'fancy',
+      ]
+      const colours = [
+        'red',
+        'yellow',
+        'blue',
+        'green',
+        'pink',
+        'brown',
+        'purple',
+        'brown',
+        'white',
+        'black',
+        'orange',
+      ]
+      const nouns = [
+        'table',
+        'chair',
+        'house',
+        'bbq',
+        'desk',
+        'car',
+        'pony',
+        'cookie',
+        'sandwich',
+        'burger',
+        'pizza',
+        'mouse',
+        'keyboard',
+      ]
+
+      const data = buildData(100)
+
+      for (const row of data) {
+        const words = row.label.value.split(' ')
+        expect(adjectives).toContain(words[0])
+        expect(colours).toContain(words[1])
+        expect(nouns).toContain(words[2])
+      }
+    })
+
+    it('should maintain ID sequence across multiple calls', () => {
+      const data1 = buildData(10)
+      const data2 = buildData(10)
+
+      const lastIdOfFirst = data1[data1.length - 1].id
+      const firstIdOfSecond = data2[0].id
+
+      expect(firstIdOfSecond).toBeGreaterThan(lastIdOfFirst)
+    })
+
+    it('should generate valid data structure', () => {
+      const data = buildData(1)
+      const row = data[0]
+
+      expect(row).toHaveProperty('id')
+      expect(row).toHaveProperty('label')
+      expect(typeof row.id).toBe('number')
+      expect(isRef(row.label)).toBe(true)
+    })
+
+    it('should handle edge case of single row', () => {
+      const data = buildData(1)
+      expect(data).toHaveLength(1)
+      expect(data[0]).toHaveProperty('id')
+      expect(data[0]).toHaveProperty('label')
+    })
+
+    it('should generate different labels for multiple rows', () => {
+      const data = buildData(100)
+      const labels = data.map(row => row.label.value)
+
+      // While labels could theoretically repeat due to randomness,
+      // with 100 rows from a large pool, we expect at least some variety
+      const uniqueLabels = new Set(labels)
+      expect(uniqueLabels.size).toBeGreaterThan(1)
+    })
+
+    it('should generate labels that can be mutated reactively', () => {
+      const data = buildData(1)
+      const row = data[0]
+      const originalLabel = row.label.value
+
+      row.label.value = 'new label'
+      expect(row.label.value).toBe('new label')
+      expect(row.label.value).not.toBe(originalLabel)
+    })
+
+    it('should handle large data generation', () => {
+      const data = buildData(10000)
+      expect(data).toHaveLength(10000)
+      expect(data[0]).toHaveProperty('id')
+      expect(data[9999]).toHaveProperty('id')
+    })
+
+    it('should generate rows with consistent structure', () => {
+      const data = buildData(50)
+
+      for (const row of data) {
+        expect(Object.keys(row).sort()).toEqual(['id', 'label'].sort())
+      }
+    })
+
+    it('should generate IDs as positive integers', () => {
+      const data = buildData(100)
+
+      for (const row of data) {
+        expect(row.id).toBeGreaterThan(0)
+        expect(Number.isInteger(row.id)).toBe(true)
+      }
+    })
+
+    it('should handle negative count by generating empty array', () => {
+      const data = buildData(-1)
+      expect(data).toHaveLength(0)
+    })
+
+    it('should handle fractional count', () => {
+      const data = buildData(5.7)
+      // For loop with i < 5.7 means i can be 0,1,2,3,4,5 (6 values)
+      expect(data.length).toBeLessThanOrEqual(6)
+      expect(data.length).toBeGreaterThanOrEqual(5)
+    })
+
+    it('should generate labels with consistent spacing', () => {
+      const data = buildData(20)
+
+      for (const row of data) {
+        const label = row.label.value
+        // Should not have leading/trailing spaces
+        expect(label).toBe(label.trim())
+        // Should have exactly 2 spaces (between 3 words)
+        expect(label.split(' ').length - 1).toBe(2)
+      }
+    })
+
+    it('should support reactive updates on labels', () => {
+      const data = buildData(1)
+      const row = data[0]
+
+      let updateCount = 0
+      const stop = row.label.value // Access to establish reactivity
+
+      row.label.value = 'updated label'
+      expect(row.label.value).toBe('updated label')
+
+      row.label.value = 'another update'
+      expect(row.label.value).toBe('another update')
+    })
+
+    it('should generate truly random labels with sufficient variety', () => {
+      const data = buildData(1000)
+      const labels = data.map(row => row.label.value)
+      const uniqueLabels = new Set(labels)
+
+      // With 1000 rows and randomness, we should have significant variety
+      // (25 adjectives * 11 colors * 13 nouns = 3575 possible combinations)
+      expect(uniqueLabels.size).toBeGreaterThan(100)
+    })
+
+    it('should not mutate input parameters', () => {
+      const count = 100
+      const originalCount = count
+      buildData(count)
+      expect(count).toBe(originalCount)
+    })
+
+    it('should handle rapid successive calls', () => {
+      const data1 = buildData(10)
+      const data2 = buildData(10)
+      const data3 = buildData(10)
+
+      expect(data1.length).toBe(10)
+      expect(data2.length).toBe(10)
+      expect(data3.length).toBe(10)
+
+      // IDs should continue incrementing
+      expect(data2[0].id).toBeGreaterThan(data1[data1.length - 1].id)
+      expect(data3[0].id).toBeGreaterThan(data2[data2.length - 1].id)
+    })
+  })
+})

+ 558 - 0
packages-private/benchmark/client/__tests__/profiling.spec.ts

@@ -0,0 +1,558 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+import { defer, wrap } from '../profiling'
+import { nextTick } from 'vue'
+
+// Mock Vue's nextTick
+vi.mock('vue', async () => {
+  const actual = await vi.importActual<typeof import('vue')>('vue')
+  return {
+    ...actual,
+    nextTick: vi.fn(() => Promise.resolve()),
+  }
+})
+
+describe('benchmark/profiling', () => {
+  let performanceNowSpy: any
+  let performanceMeasureSpy: any
+
+  beforeEach(() => {
+    // Clear global state before each test
+    globalThis.recordTime = true
+    globalThis.doProfile = false
+    globalThis.reactivity = false
+    // Clear times object instead of replacing it (module references it)
+    if (globalThis.times) {
+      Object.keys(globalThis.times).forEach(key => {
+        delete globalThis.times[key]
+      })
+    }
+
+    // Mock DOM APIs
+    if (typeof document === 'undefined') {
+      ;(global as any).document = {
+        body: {
+          classList: {
+            add: vi.fn(),
+            remove: vi.fn(),
+          },
+        },
+        getElementById: vi.fn(() => ({
+          textContent: '',
+        })),
+      }
+    } else {
+      // Reset existing mocks
+      ;(document.body.classList.add as any) = vi.fn()
+      ;(document.body.classList.remove as any) = vi.fn()
+      ;(document.getElementById as any) = vi.fn(() => ({
+        textContent: '',
+      }))
+    }
+
+    // Spy on performance API
+    performanceNowSpy = vi.spyOn(performance, 'now')
+    performanceMeasureSpy = vi
+      .spyOn(performance, 'measure')
+      .mockReturnValue({ duration: 10 } as any)
+    vi.spyOn(performance, 'clearMarks')
+    vi.spyOn(performance, 'clearMeasures')
+
+    // Mock console
+    global.console = {
+      ...console,
+      log: vi.fn(),
+      profile: vi.fn(),
+      profileEnd: vi.fn(),
+    }
+
+    // Mock requestIdleCallback
+    if (typeof requestIdleCallback === 'undefined') {
+      ;(global as any).requestIdleCallback = vi.fn((cb: Function) => {
+        setTimeout(cb, 0)
+      })
+    }
+  })
+
+  afterEach(() => {
+    vi.clearAllMocks()
+    vi.restoreAllMocks()
+  })
+
+  describe('defer', () => {
+    it('should return a Promise', () => {
+      const result = defer()
+      expect(result).toBeInstanceOf(Promise)
+    })
+
+    it('should resolve after requestIdleCallback', async () => {
+      const spy = vi.fn()
+      await defer()
+      spy()
+      expect(spy).toHaveBeenCalled()
+    })
+
+    it('should use requestIdleCallback', async () => {
+      const requestIdleCallbackSpy = vi.spyOn(
+        globalThis,
+        'requestIdleCallback',
+      )
+      await defer()
+      expect(requestIdleCallbackSpy).toHaveBeenCalled()
+    })
+  })
+
+  describe('wrap', () => {
+    it('should return a function', () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+      expect(typeof wrapped).toBe('function')
+    })
+
+    it('should execute the wrapped function when recordTime is false', async () => {
+      globalThis.recordTime = false
+      const fn = vi.fn(() => 42)
+      const wrapped = wrap('test', fn)
+
+      const result = await wrapped()
+
+      expect(fn).toHaveBeenCalled()
+      expect(result).toBe(42)
+    })
+
+    it('should pass arguments to the wrapped function', async () => {
+      globalThis.recordTime = false
+      const fn = vi.fn((a: number, b: number) => a + b)
+      const wrapped = wrap('test', fn)
+
+      const result = await wrapped(5, 3)
+
+      expect(fn).toHaveBeenCalledWith(5, 3)
+      expect(result).toBe(8)
+    })
+
+    it('should remove "done" class from body before execution', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(document.body.classList.remove).toHaveBeenCalledWith('done')
+    })
+
+    it('should add "done" class to body after execution', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(document.body.classList.add).toHaveBeenCalledWith('done')
+    })
+
+    it('should measure execution time', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(globalThis.times.test).toBeDefined()
+      expect(globalThis.times.test.length).toBe(1)
+      expect(typeof globalThis.times.test[0]).toBe('number')
+    })
+
+    it('should accumulate times across multiple calls', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+      await wrapped()
+      await wrapped()
+
+      expect(globalThis.times.test.length).toBe(3)
+    })
+
+    it('should log performance metrics', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(console.log).toHaveBeenCalled()
+      const logCall = (console.log as any).mock.calls[0][0]
+      expect(logCall).toContain('test:')
+      expect(logCall).toContain('min:')
+      expect(logCall).toContain('max:')
+      expect(logCall).toContain('median:')
+      expect(logCall).toContain('mean:')
+      expect(logCall).toContain('time:')
+      expect(logCall).toContain('std:')
+    })
+
+    it('should update time element in DOM', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+      const timeElement = { textContent: '' }
+
+      ;(document.getElementById as any).mockReturnValue(timeElement)
+
+      await wrapped()
+
+      expect(document.getElementById).toHaveBeenCalledWith('time')
+      expect(timeElement.textContent).toContain('test:')
+    })
+
+    it('should call console.profile when doProfile is true', async () => {
+      globalThis.doProfile = true
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(console.profile).toHaveBeenCalledWith('test')
+      expect(console.profileEnd).toHaveBeenCalledWith('test')
+    })
+
+    it('should not call console.profile when doProfile is false', async () => {
+      globalThis.doProfile = false
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(console.profile).not.toHaveBeenCalled()
+      expect(console.profileEnd).not.toHaveBeenCalled()
+    })
+
+    it('should use performance.measure when reactivity is true', async () => {
+      globalThis.reactivity = true
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(performance.measure).toHaveBeenCalledWith(
+        'flushJobs-measure',
+        'flushJobs-start',
+        'flushJobs-end',
+      )
+      expect(performance.clearMarks).toHaveBeenCalled()
+      expect(performance.clearMeasures).toHaveBeenCalled()
+    })
+
+    it('should use performance.now when reactivity is false', async () => {
+      globalThis.reactivity = false
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(performanceNowSpy).toHaveBeenCalled()
+    })
+
+    it('should track separate times for different IDs', async () => {
+      const fn1 = vi.fn()
+      const fn2 = vi.fn()
+      const wrapped1 = wrap('operation1', fn1)
+      const wrapped2 = wrap('operation2', fn2)
+
+      await wrapped1()
+      await wrapped2()
+
+      expect(globalThis.times.operation1).toBeDefined()
+      expect(globalThis.times.operation2).toBeDefined()
+      expect(globalThis.times.operation1.length).toBe(1)
+      expect(globalThis.times.operation2.length).toBe(1)
+    })
+
+    it('should calculate correct statistics', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      // Mock performance.now to return predictable values
+      let callCount = 0
+      performanceNowSpy.mockImplementation(() => {
+        callCount++
+        return callCount * 10
+      })
+
+      await wrapped()
+      await wrapped()
+      await wrapped()
+
+      expect(globalThis.times.test.length).toBe(3)
+    })
+
+    it('should handle errors in wrapped function gracefully', async () => {
+      const fn = vi.fn(() => {
+        throw new Error('Test error')
+      })
+      const wrapped = wrap('test', fn)
+
+      await expect(wrapped()).rejects.toThrow('Test error')
+    })
+
+    it('should work with async functions', async () => {
+      const fn = vi.fn(async () => {
+        await new Promise(resolve => setTimeout(resolve, 10))
+        return 'async result'
+      })
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(fn).toHaveBeenCalled()
+    })
+
+    it('should include run count in log message', async () => {
+      // Use a unique ID to avoid shared state
+      const fn = vi.fn()
+      const wrapped = wrap('uniqueTest' + Date.now(), fn)
+
+      await wrapped()
+      await wrapped()
+      await wrapped()
+
+      const lastLogCall = (console.log as any).mock.calls[2][0]
+      expect(lastLogCall).toContain('over 3 runs')
+    })
+
+    it('should format time values to 2 decimal places', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      // Mock to return a value with many decimals
+      performanceNowSpy
+        .mockReturnValueOnce(100.123456789)
+        .mockReturnValueOnce(105.987654321)
+
+      await wrapped()
+
+      const logCall = (console.log as any).mock.calls[0][0]
+      // Should contain formatted numbers
+      expect(logCall).toMatch(/\d+\.\d{2}/)
+    })
+
+    it('should initialize times object for new ID', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('newOperation', fn)
+
+      expect(globalThis.times.newOperation).toBeUndefined()
+
+      await wrapped()
+
+      expect(globalThis.times.newOperation).toBeDefined()
+      expect(Array.isArray(globalThis.times.newOperation)).toBe(true)
+    })
+
+    it('should wait for nextTick before and after execution', async () => {
+      // This test verifies that the function waits appropriately
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      const startTime = Date.now()
+      await wrapped()
+      const endTime = Date.now()
+
+      // Should take some time due to nextTick calls
+      expect(fn).toHaveBeenCalled()
+    })
+  })
+
+  describe('global state', () => {
+    it('should initialize recordTime to true', () => {
+      expect(globalThis.recordTime).toBe(true)
+    })
+
+    it('should initialize doProfile to false', () => {
+      expect(globalThis.doProfile).toBe(false)
+    })
+
+    it('should initialize reactivity to false', () => {
+      expect(globalThis.reactivity).toBe(false)
+    })
+
+    it('should initialize times as empty object', () => {
+      // Clear and check
+      Object.keys(globalThis.times).forEach(key => {
+        delete globalThis.times[key]
+      })
+      expect(Object.keys(globalThis.times)).toEqual([])
+    })
+  })
+
+  describe('edge cases and additional coverage', () => {
+    it('should handle functions that return values', async () => {
+      const fn = vi.fn(() => 'return value')
+      const wrapped = wrap('test', fn)
+
+      await wrapped()
+
+      expect(fn).toHaveBeenCalled()
+    })
+
+    it('should handle functions with complex arguments', async () => {
+      globalThis.recordTime = false
+      const fn = vi.fn((obj: any, arr: any[], num: number) => {
+        return obj.key + arr.length + num
+      })
+      const wrapped = wrap('test', fn)
+
+      const result = await wrapped({ key: 'value' }, [1, 2, 3], 42)
+
+      expect(fn).toHaveBeenCalledWith({ key: 'value' }, [1, 2, 3], 42)
+    })
+
+    it('should handle zero execution time', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      performanceNowSpy.mockReturnValueOnce(100).mockReturnValueOnce(100)
+
+      await wrapped()
+
+      expect(globalThis.times.test).toBeDefined()
+      expect(globalThis.times.test[0]).toBe(0)
+    })
+
+    it('should handle negative time differences gracefully', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test', fn)
+
+      // Simulate clock going backwards
+      performanceNowSpy.mockReturnValueOnce(100).mockReturnValueOnce(99)
+
+      await wrapped()
+
+      expect(globalThis.times.test).toBeDefined()
+      expect(globalThis.times.test[0]).toBe(-1)
+    })
+
+    it('should calculate stats correctly with single value', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('singleValue', fn)
+
+      await wrapped()
+
+      const logCall = (console.log as any).mock.calls[0][0]
+      expect(logCall).toContain('over 1 runs')
+      // min, max, median, mean should all be the same
+      expect(logCall).toContain('min:')
+      expect(logCall).toContain('max:')
+      expect(logCall).toContain('median:')
+    })
+
+    it('should handle very large time values', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('largeTime', fn)
+
+      performanceNowSpy.mockReturnValueOnce(0).mockReturnValueOnce(999999.999)
+
+      await wrapped()
+
+      expect(globalThis.times.largeTime[0]).toBeGreaterThan(999999)
+    })
+
+    it('should handle concurrent wrap calls with different IDs', async () => {
+      const fn1 = vi.fn()
+      const fn2 = vi.fn()
+      const wrapped1 = wrap('concurrent1', fn1)
+      const wrapped2 = wrap('concurrent2', fn2)
+
+      // Call both concurrently
+      await Promise.all([wrapped1(), wrapped2()])
+
+      expect(globalThis.times.concurrent1).toBeDefined()
+      expect(globalThis.times.concurrent2).toBeDefined()
+      expect(fn1).toHaveBeenCalled()
+      expect(fn2).toHaveBeenCalled()
+    })
+
+    it('should handle functions that modify external state', async () => {
+      globalThis.recordTime = false
+      let externalState = 0
+      const fn = vi.fn(() => {
+        externalState++
+      })
+      const wrapped = wrap('stateModifier', fn)
+
+      await wrapped()
+
+      expect(fn).toHaveBeenCalled()
+      expect(externalState).toBe(1)
+    })
+
+    it('should handle empty string ID', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('', fn)
+
+      await wrapped()
+
+      expect(globalThis.times['']).toBeDefined()
+    })
+
+    it('should handle special characters in ID', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('test-with-dashes_and_underscores.dots', fn)
+
+      await wrapped()
+
+      expect(globalThis.times['test-with-dashes_and_underscores.dots']).toBeDefined()
+    })
+
+    it('should update DOM correctly with special characters in message', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('special<>&"', fn)
+      const timeElement = { textContent: '' }
+
+      ;(document.getElementById as any).mockReturnValue(timeElement)
+
+      await wrapped()
+
+      expect(timeElement.textContent).toContain('special<>&"')
+    })
+
+    it('should calculate standard deviation correctly', async () => {
+      const fn = vi.fn()
+      const wrapped = wrap('stdTest', fn)
+
+      // Create predictable time values
+      performanceNowSpy
+        .mockReturnValueOnce(0)
+        .mockReturnValueOnce(10) // diff: 10
+        .mockReturnValueOnce(0)
+        .mockReturnValueOnce(20) // diff: 20
+        .mockReturnValueOnce(0)
+        .mockReturnValueOnce(30) // diff: 30
+
+      await wrapped()
+      await wrapped()
+      await wrapped()
+
+      expect(globalThis.times.stdTest).toEqual([10, 20, 30])
+      // Mean is 20, std should be calculated
+      const logCall = (console.log as any).mock.calls[2][0]
+      expect(logCall).toContain('std:')
+    })
+
+    it('should clear performance marks and measures only when reactivity is true', async () => {
+      const fn = vi.fn()
+
+      // Test with reactivity true
+      globalThis.reactivity = true
+      const wrapped1 = wrap('reactivityTest', fn)
+      await wrapped1()
+
+      expect(performance.clearMarks).toHaveBeenCalled()
+      expect(performance.clearMeasures).toHaveBeenCalled()
+
+      vi.clearAllMocks()
+
+      // Test with reactivity false
+      globalThis.reactivity = false
+      const wrapped2 = wrap('noReactivityTest', fn)
+      await wrapped2()
+
+      expect(performance.clearMarks).not.toHaveBeenCalled()
+      expect(performance.clearMeasures).not.toHaveBeenCalled()
+    })
+  })
+})