From 48be5593d367b12b8218f06262183022788c23ce Mon Sep 17 00:00:00 2001 From: ThatGuySam Date: Fri, 27 Dec 2024 15:07:28 -0600 Subject: [PATCH] update: refactor primary prebuild tests to vitest --- test/_disabled/prebuild/index.js | 238 ------------------------------- test/prebuild/index.test.js | 172 ++++++++++++++++++++++ 2 files changed, 172 insertions(+), 238 deletions(-) delete mode 100644 test/_disabled/prebuild/index.js create mode 100644 test/prebuild/index.test.js diff --git a/test/_disabled/prebuild/index.js b/test/_disabled/prebuild/index.js deleted file mode 100644 index c1381ca..0000000 --- a/test/_disabled/prebuild/index.js +++ /dev/null @@ -1,238 +0,0 @@ -import fs from 'fs-extra' -import test from 'ava' -// import MarkdownIt from 'markdown-it' - -import { isValidHttpUrl } from '~/helpers/check-types.js' -import { buildReadmeAppList } from '~/helpers/build-app-list.js' -import { - matchesWholeWord, - fuzzyMatchesWholeWord, - eitherMatches -} from '~/helpers/matching.js' -import { - PaginatedList -} from '~/helpers/api/pagination.js' - - -require('dotenv').config() - -const allowedTitleCharacters = new Set( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -+:_.®/\()音乐体验版'.split('') ) - -// Detect Emojis(Extended Pictograph) in string -// https://stackoverflow.com/a/64007175/1397641 -function hasEmoji ( string ) { - return /\p{Extended_Pictographic}/u.test( string ) -} - -test.before(async t => { - const readmeFileContent = await fs.readFile('./README.md', 'utf-8') - - - // Store sitemap urls to context - t.context.readmeFileContent = readmeFileContent - t.context.readmeAppList = buildReadmeAppList({ - readmeContent: t.context.readmeFileContent, - scanListMap: new Map(), - commits: [] - }) -}) - -test('README Apps are formated correctly', (t) => { - // console.log('t.context.sitemapUrls', t.context.sitemapUrls) - - const { - readmeAppList - } = t.context - - // Store found apps so we can check for duplicates - const foundApps = new Set() - - // Store found invalid apps so we can count and report them - const invalidApps = new Set() - - - for (const readmeApp of readmeAppList) { - const cleanedAppName = readmeApp.name//.toLowerCase() - - // Check that app has not already been found - if (foundApps.has(cleanedAppName)) { - t.fail(`Duplicate app found: ${readmeApp.name}`) - invalidApps.add(cleanedAppName) - } - // Store this app so we can check for future duplicates - foundApps.add(cleanedAppName) - - // Check that all related links urls are valid - for (const relatedLink of readmeApp.relatedLinks) { - if ( !isValidHttpUrl( relatedLink.href ) ) { - t.log('relatedLink.href', readmeApp.name, relatedLink.href) - - t.fail(`README App ${readmeApp.name} does not have valid url`, readmeApp.url) - invalidApps.add(cleanedAppName) - } - } - - - // Check that status text is free of markdown - if ( readmeApp.text.includes('](') ) { - t.fail(`README App ${readmeApp.name} markdown in status text`) - invalidApps.add(cleanedAppName) - } - - // Check that status has an emoji - if ( hasEmoji( readmeApp.text ) === false ) { - t.fail(`README App ${readmeApp.name} does not have emoji`) - invalidApps.add(cleanedAppName) - } - - // Check for not allowed characters in app name - for ( const character of cleanedAppName ) { - if ( !allowedTitleCharacters.has( character ) ) { - - // badCharacter = readmeApp.name[firstBadCharacterIndex] - - // t.log( readmeApp ) - t.fail(`README App Title ${readmeApp.name} has non-alphanumeric character ${character}(charCode ${character.charCodeAt(0)})`) - invalidApps.add(cleanedAppName) - } - } - - } - - t.log( readmeAppList.length - invalidApps.size, 'valid apps found' ) - t.log( readmeAppList.length, 'apps found in README' ) - - t.pass() -}) - - -function sortAppsAlphabetically ( a, b ) { - return a.name.localeCompare(b.name) -} - - -test('README Apps are in alphbetical order', (t) => { - - const { - readmeAppList - } = t.context - - const appsByCategory = new Map() - - - - // Group apps by category - for ( const readmeApp of readmeAppList ) { - const category = readmeApp.category.slug - - if ( !appsByCategory.has(category) ) { - appsByCategory.set(category, []) - } - - appsByCategory.get( category ).push(readmeApp) - } - - // Sort apps in groups alphabetically - for ( const [ category, apps ] of appsByCategory ) { - - const unsortedApps = apps.slice() - - // Sort apps in category in place - apps.sort(sortAppsAlphabetically) - - // Check sorted sorted apps against unsorted apps - for ( const [ index, unsortedApp ] of unsortedApps.entries() ) { - const sortedApp = apps[index] - - if ( sortedApp.slug !== unsortedApp.slug ) { - t.fail(`README App at index ${index} of ${category} is ${unsortedApp.name} but should be ${sortedApp.name}`) - } - } - } - - t.pass() -}) - - - -const namesWithPlusses = [ - 'Xournal++', - 'Notepad++' -] - -test('Can match names with pluses', (t) => { - - - - // Sort apps in groups alphabetically - for ( const nameWithPluses of namesWithPlusses ) { - - const haystack = `FDKLS:KF ${nameWithPluses}NDFLSKFLSJDK` - - t.assert( matchesWholeWord( nameWithPluses, haystack ) ) - - t.assert( fuzzyMatchesWholeWord( nameWithPluses, haystack ) ) - - t.assert( eitherMatches( nameWithPluses, haystack ) ) - t.assert( eitherMatches( haystack, nameWithPluses ) ) - } - - t.pass() -}) - - -test('Can paginate', async (t) => { - const cases = [ - { - from: { - list: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ], - perPage: 2 - }, - expect: { - pageCount: 5, - pages: [ - { - number: 1, - hasNextPage: true, - hasPreviousPage: false, - items: [1, 2], - json: '[1,2]' - }, - { - number: 2, - hasNextPage: true, - hasPreviousPage: true, - items: [3, 4], - json: '[3,4]' - }, - - // Last page should have less than perPage items - { - number: 5, - hasNextPage: false, - hasPreviousPage: true, - items: [9], - json: '[9]' - } - ] - } - } - ] - - for ( const { from, expect } of cases ) { - - const paginatedList = new PaginatedList( from ) - - // Assert that page count is correct - t.is( paginatedList.pageCount, expect.pageCount, 'pageCount is incorrect' ) - - // Assert that the pages we're expecting are there - for ( const expectedPage of expect.pages ) { - // Get respective output page - const outputPage = paginatedList.pages[ expectedPage.number - 1 ] - - t.deepEqual( outputPage, expectedPage, `Page ${ expectedPage.number } is an unexpected structure` ) - } - } - -} ) diff --git a/test/prebuild/index.test.js b/test/prebuild/index.test.js new file mode 100644 index 0000000..4aab3f8 --- /dev/null +++ b/test/prebuild/index.test.js @@ -0,0 +1,172 @@ +import fs from 'fs-extra' +import { describe, it, expect, beforeAll } from 'vitest' +import { isValidHttpUrl } from '~/helpers/check-types.js' +import { buildReadmeAppList } from '~/helpers/build-app-list.js' +import { + matchesWholeWord, + fuzzyMatchesWholeWord, + eitherMatches +} from '~/helpers/matching.js' +import { PaginatedList } from '~/helpers/api/pagination.js' + +require('dotenv').config() + +const allowedTitleCharacters = new Set( + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -+:_.®/\()音乐体验版'.split('') +) + +/** + * Detect Emojis(Extended Pictograph) in string + * https://stackoverflow.com/a/64007175/1397641 + */ +function hasEmoji(string) { + return /\p{Extended_Pictographic}/u.test(string) +} + +describe('README Validation', () => { + let readmeFileContent + let readmeAppList + + beforeAll(async () => { + readmeFileContent = await fs.readFile('./README.md', 'utf-8') + readmeAppList = buildReadmeAppList({ + readmeContent: readmeFileContent, + scanListMap: new Map(), + commits: [] + }) + }) + + // User Story: As a maintainer, I want to ensure README apps are properly formatted + describe('app formatting', () => { + it('should have correctly formatted apps', () => { + const foundApps = new Set() + const invalidApps = new Set() + + for (const readmeApp of readmeAppList) { + const cleanedAppName = readmeApp.name + + // Check for duplicates + if (foundApps.has(cleanedAppName)) { + expect.fail(`Duplicate app found: ${readmeApp.name}`) + invalidApps.add(cleanedAppName) + } + foundApps.add(cleanedAppName) + + // Validate related links + for (const relatedLink of readmeApp.relatedLinks) { + expect(isValidHttpUrl(relatedLink.href)) + .toBe(true, `README App ${readmeApp.name} has invalid URL: ${relatedLink.href}`) + } + + // Check status text formatting + expect(readmeApp.text.includes('](')) + .toBe(false, `README App ${readmeApp.name} has markdown in status text`) + + // Verify emoji presence + expect(hasEmoji(readmeApp.text)) + .toBe(true, `README App ${readmeApp.name} does not have emoji`) + + // Validate app name characters + for (const character of cleanedAppName) { + expect(allowedTitleCharacters.has(character)) + .toBe(true, `README App Title ${readmeApp.name} has invalid character ${character}`) + } + } + + console.log(`${readmeAppList.length - invalidApps.size} valid apps found`) + console.log(`${readmeAppList.length} total apps found in README`) + }) + }) + + // User Story: As a maintainer, I want apps sorted alphabetically within categories + describe('app sorting', () => { + it('should have apps in alphabetical order within categories', () => { + const appsByCategory = new Map() + + // Group apps by category + for (const readmeApp of readmeAppList) { + const category = readmeApp.category.slug + if (!appsByCategory.has(category)) { + appsByCategory.set(category, []) + } + appsByCategory.get(category).push(readmeApp) + } + + // Verify sorting within categories + for (const [category, apps] of appsByCategory) { + const unsortedApps = [...apps] + const sortedApps = [...apps].sort((a, b) => a.name.localeCompare(b.name)) + + sortedApps.forEach((sortedApp, index) => { + expect(sortedApp.slug) + .toBe(unsortedApps[index].slug, + `App at index ${index} of ${category} is out of order`) + }) + } + }) + }) +}) + +// User Story: As a developer, I want to ensure special characters in names are handled correctly +describe('Name Matching', () => { + const namesWithPlusses = ['Xournal++', 'Notepad++'] + + it('should match names containing plus symbols', () => { + for (const nameWithPlusses of namesWithPlusses) { + const haystack = `FDKLS:KF ${nameWithPlusses}NDFLSKFLSJDK` + + expect(matchesWholeWord(nameWithPlusses, haystack)).toBe(true) + expect(fuzzyMatchesWholeWord(nameWithPlusses, haystack)).toBe(true) + expect(eitherMatches(nameWithPlusses, haystack)).toBe(true) + expect(eitherMatches(haystack, nameWithPlusses)).toBe(true) + } + }) +}) + +// User Story: As a developer, I want to ensure pagination works correctly +describe('Pagination', () => { + it('should paginate lists correctly', () => { + const testCase = { + list: [1, 2, 3, 4, 5, 6, 7, 8, 9], + perPage: 2, + expectedPageCount: 5, + expectedPages: [ + { + number: 1, + hasNextPage: true, + hasPreviousPage: false, + items: [1, 2], + json: '[1,2]' + }, + { + number: 2, + hasNextPage: true, + hasPreviousPage: true, + items: [3, 4], + json: '[3,4]' + }, + { + number: 5, + hasNextPage: false, + hasPreviousPage: true, + items: [9], + json: '[9]' + } + ] + } + + const paginatedList = new PaginatedList({ + list: testCase.list, + perPage: testCase.perPage + }) + + expect(paginatedList.pageCount) + .toBe(testCase.expectedPageCount, 'Incorrect page count') + + testCase.expectedPages.forEach(expectedPage => { + const actualPage = paginatedList.pages[expectedPage.number - 1] + expect(actualPage) + .toEqual(expectedPage, `Page ${expectedPage.number} has unexpected structure`) + }) + }) +})