[READ-ONLY] a fast, modern browser for the npm registry

test: add property based tests via fast-check (#791)

Co-authored-by: Daniel Roe <daniel@roe.dev>

authored by

Nicolas DUBIEN
Daniel Roe
and committed by
GitHub
0c03bb12 e96ff212

+127
+1
package.json
··· 106 106 "@vitest/coverage-v8": "4.0.18", 107 107 "@vue/test-utils": "2.4.6", 108 108 "axe-core": "4.11.1", 109 + "fast-check": "4.5.3", 109 110 "fast-npm-meta": "1.0.0", 110 111 "knip": "5.83.0", 111 112 "lint-staged": "16.2.7",
+16
pnpm-lock.yaml
··· 225 225 axe-core: 226 226 specifier: 4.11.1 227 227 version: 4.11.1 228 + fast-check: 229 + specifier: 4.5.3 230 + version: 4.5.3 228 231 fast-npm-meta: 229 232 specifier: 1.0.0 230 233 version: 1.0.0 ··· 5685 5688 resolution: {integrity: sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==} 5686 5689 engines: {node: '>=18'} 5687 5690 5691 + fast-check@4.5.3: 5692 + resolution: {integrity: sha512-IE9csY7lnhxBnA8g/WI5eg/hygA6MGWJMSNfFRrBlXUciADEhS1EDB0SIsMSvzubzIlOBbVITSsypCsW717poA==} 5693 + engines: {node: '>=12.17.0'} 5694 + 5688 5695 fast-deep-equal@3.1.3: 5689 5696 resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 5690 5697 ··· 7905 7912 resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 7906 7913 engines: {node: '>=6'} 7907 7914 7915 + pure-rand@7.0.1: 7916 + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} 7917 + 7908 7918 qs@6.14.1: 7909 7919 resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} 7910 7920 engines: {node: '>=0.6'} ··· 15807 15817 15808 15818 fake-indexeddb@6.2.5: {} 15809 15819 15820 + fast-check@4.5.3: 15821 + dependencies: 15822 + pure-rand: 7.0.1 15823 + 15810 15824 fast-deep-equal@3.1.3: {} 15811 15825 15812 15826 fast-fifo@1.3.2: {} ··· 19005 19019 punycode.js@2.3.1: {} 19006 19020 19007 19021 punycode@2.3.1: {} 19022 + 19023 + pure-rand@7.0.1: {} 19008 19024 19009 19025 qs@6.14.1: 19010 19026 dependencies:
+69
test/unit/server/utils/docs/text.spec.ts
··· 1 1 import { describe, expect, it } from 'vitest' 2 + import * as fc from 'fast-check' 2 3 import { 3 4 escapeHtml, 4 5 parseJsDocLinks, ··· 39 40 const ESC = String.fromCharCode(27) 40 41 const input = `object is ReactElement${ESC}[0m${ESC}[38;5;12m<${ESC}[0mP${ESC}[38;5;12m>${ESC}[0m` 41 42 expect(stripAnsi(input)).toBe('object is ReactElement<P>') 43 + }) 44 + 45 + it('should strip everything in one pass', () => { 46 + fc.assert( 47 + fc.property(fc.string(), input => { 48 + const stripped = stripAnsi(input) 49 + expect(stripAnsi(stripped)).toBe(stripped) 50 + }), 51 + ) 42 52 }) 43 53 }) 44 54 ··· 123 133 it('should handle http URLs (not just https)', () => { 124 134 const result = parseJsDocLinks('{@link http://example.com}', emptyLookup) 125 135 expect(result).toContain('href="http://example.com"') 136 + }) 137 + 138 + it('should convert external URLs using {@link url} to links', () => { 139 + fc.assert( 140 + fc.property(fc.webUrl(), url => { 141 + const result = parseJsDocLinks(`{@link ${url}}`, emptyLookup) 142 + expect(result).toContain(`href="${escapeHtml(url)}"`) 143 + expect(result).toContain('target="_blank"') 144 + expect(result).toContain('rel="noreferrer"') 145 + expect(result).toContain(escapeHtml(url)) 146 + }), 147 + ) 148 + }) 149 + 150 + it('should convert external URLs using {@link url text} to links', () => { 151 + fc.assert( 152 + fc.property(fc.webUrl(), fc.stringMatching(/^[^}\s][^}]+[^}\s]$/), (url, text) => { 153 + const result = parseJsDocLinks(`{@link ${url} ${text}}`, emptyLookup) 154 + expect(result).toContain(`href="${escapeHtml(url)}"`) 155 + expect(result).toContain('target="_blank"') 156 + expect(result).toContain('rel="noreferrer"') 157 + expect(result).toContain(escapeHtml(text)) 158 + }), 159 + ) 160 + }) 161 + 162 + it('should be able to treat correctly several external URLs at the middle of a text', () => { 163 + const surrounding = fc.stringMatching(/^[^{]*$/) 164 + const link = fc.record({ 165 + url: fc.webUrl(), 166 + label: fc.option(fc.stringMatching(/^[^}\s][^}]+[^}\s]$/)), 167 + before: surrounding, 168 + after: surrounding, 169 + }) 170 + fc.assert( 171 + fc.property(fc.array(link, { minLength: 1 }), content => { 172 + let docString = '' 173 + const expectedUrls = [] 174 + for (const chunk of content) { 175 + if (chunk.before.length !== 0 || docString.length !== 0) { 176 + docString += `${chunk.before} ` 177 + } 178 + if (chunk.label === null) { 179 + docString += `{@link ${chunk.url}}` 180 + expectedUrls.push(chunk.url) 181 + } else { 182 + docString += `{@link ${chunk.url} ${chunk.label}}` 183 + expectedUrls.push(chunk.url) 184 + } 185 + if (chunk.after.length !== 0) { 186 + docString += ` ${chunk.after}` 187 + } 188 + } 189 + const result = parseJsDocLinks(docString, emptyLookup) 190 + for (const url of expectedUrls) { 191 + expect(result).toContain(`href="${escapeHtml(url)}"`) 192 + } 193 + }), 194 + ) 126 195 }) 127 196 }) 128 197
+41
test/unit/shared/utils/async.spec.ts
··· 1 1 import { describe, expect, it, vi } from 'vitest' 2 + import * as fc from 'fast-check' 2 3 import { mapWithConcurrency } from '../../../../shared/utils/async' 3 4 4 5 describe('mapWithConcurrency', () => { ··· 91 92 92 93 // Should only have 3 concurrent since we only have 3 items 93 94 expect(maxConcurrent).toBe(3) 95 + }) 96 + 97 + it('waits for all tasks to succeed and return them in order whatever their count and the concurrency', async () => { 98 + await fc.assert( 99 + fc.asyncProperty( 100 + fc.array(fc.anything()), 101 + fc.integer({ min: 1 }), 102 + fc.scheduler(), 103 + async (items, concurrency, s) => { 104 + const fn = s.scheduleFunction(async item => item) 105 + const results = await s.waitFor(mapWithConcurrency(items, fn, concurrency)) 106 + expect(results).toEqual(items) 107 + }, 108 + ), 109 + ) 110 + }) 111 + 112 + it('not run more than concurrency tasks in parallel', async () => { 113 + await fc.assert( 114 + fc.asyncProperty( 115 + fc.array(fc.anything()), 116 + fc.integer({ min: 1 }), 117 + fc.scheduler(), 118 + async (items, concurrency, s) => { 119 + let tooManyRunningTasksEncountered = false 120 + let currentlyRunning = 0 121 + const fn = async (item: (typeof items)[number]) => { 122 + currentlyRunning++ 123 + if (currentlyRunning > concurrency) { 124 + tooManyRunningTasksEncountered = true 125 + } 126 + const task = s.schedule(Promise.resolve(item)) 127 + task.then(() => currentlyRunning--) // this task always succeeds by construct 128 + return task 129 + } 130 + await s.waitFor(mapWithConcurrency(items, fn, concurrency)) 131 + expect(tooManyRunningTasksEncountered).toBe(false) 132 + }, 133 + ), 134 + ) 94 135 }) 95 136 })