diff options
author | João Ferreiro <ferreiro@pinkroom.dev> | 2022-12-22 15:32:39 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-22 09:32:39 -0600 |
commit | 7517b65dcd676f36d38f31c991929c32168b3e12 (patch) | |
tree | 65793d2575b205365c2997b4bbddc1ba6424d2ba /__tests__/lib/string.test.ts | |
parent | 4913a07e3365d2004e67e9131dd4b4c15094dd33 (diff) | |
download | voidsky-7517b65dcd676f36d38f31c991929c32168b3e12.tar.zst |
Unit testing (#32)
* add testing lib * remove coverage folder from git * finished basic test setup * fix tests typescript and import paths * add first snapshot * testing utils * rename test files; update script flags; ++tests * testing utils functions * testing downloadAndResize wip * remove download test * specify unwanted coverage paths; remove update snapshots flag * fix strings tests * testing downloadAndResize method * increasing testing * fixing snapshots wip * fixed shell mobile snapshot * adding snapshots for the screens * fix onboard snapshot * fix typescript issues * fix TabsSelector snapshot * Account for testing device's locale in ago() tests * Remove platform detection on regex Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Diffstat (limited to '__tests__/lib/string.test.ts')
-rw-r--r-- | __tests__/lib/string.test.ts | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/__tests__/lib/string.test.ts b/__tests__/lib/string.test.ts new file mode 100644 index 000000000..d8a56b36b --- /dev/null +++ b/__tests__/lib/string.test.ts @@ -0,0 +1,532 @@ +import { + extractEntities, + detectLinkables, + extractHtmlMeta, + pluralize, + makeRecordUri, + ago, + makeValidHandle, + createFullHandle, + enforceLen, + cleanError, + toNiceDomain, + toShortUrl, + toShareUrl, +} from '../../src/lib/strings' + +describe('extractEntities', () => { + const knownHandles = new Set(['handle.com', 'full123.test-of-chars']) + const inputs = [ + 'no mention', + '@handle.com middle end', + 'start @handle.com end', + 'start middle @handle.com', + '@handle.com @handle.com @handle.com', + '@full123.test-of-chars', + 'not@right', + '@handle.com!@#$chars', + '@handle.com\n@handle.com', + 'parenthetical (@handle.com)', + 'start https://middle.com end', + 'start https://middle.com/foo/bar end', + 'start https://middle.com/foo/bar?baz=bux end', + 'start https://middle.com/foo/bar?baz=bux#hash end', + 'https://start.com/foo/bar?baz=bux#hash middle end', + 'start middle https://end.com/foo/bar?baz=bux#hash', + 'https://newline1.com\nhttps://newline2.com', + 'start middle.com end', + 'start middle.com/foo/bar end', + 'start middle.com/foo/bar?baz=bux end', + 'start middle.com/foo/bar?baz=bux#hash end', + 'start.com/foo/bar?baz=bux#hash middle end', + 'start middle end.com/foo/bar?baz=bux#hash', + 'newline1.com\nnewline2.com', + 'not.. a..url ..here', + 'e.g.', + 'something-cool.jpg', + 'website.com.jpg', + 'e.g./foo', + 'website.com.jpg/foo', + 'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', + 'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/ ', + 'https://foo.com https://bar.com/whatever https://baz.com', + 'punctuation https://foo.com, https://bar.com/whatever; https://baz.com.', + 'parenthentical (https://foo.com)', + 'except for https://foo.com/thing_(cool)', + ] + interface Output { + type: string + value: string + noScheme?: boolean + } + const outputs: Output[][] = [ + [], + [{type: 'mention', value: 'handle.com'}], + [{type: 'mention', value: 'handle.com'}], + [{type: 'mention', value: 'handle.com'}], + [ + {type: 'mention', value: 'handle.com'}, + {type: 'mention', value: 'handle.com'}, + {type: 'mention', value: 'handle.com'}, + ], + [ + { + type: 'mention', + value: 'full123.test-of-chars', + }, + ], + [], + [{type: 'mention', value: 'handle.com'}], + [ + {type: 'mention', value: 'handle.com'}, + {type: 'mention', value: 'handle.com'}, + ], + [{type: 'mention', value: 'handle.com'}], + [{type: 'link', value: 'https://middle.com'}], + [{type: 'link', value: 'https://middle.com/foo/bar'}], + [{type: 'link', value: 'https://middle.com/foo/bar?baz=bux'}], + [{type: 'link', value: 'https://middle.com/foo/bar?baz=bux#hash'}], + [{type: 'link', value: 'https://start.com/foo/bar?baz=bux#hash'}], + [{type: 'link', value: 'https://end.com/foo/bar?baz=bux#hash'}], + [ + {type: 'link', value: 'https://newline1.com'}, + {type: 'link', value: 'https://newline2.com'}, + ], + [{type: 'link', value: 'middle.com', noScheme: true}], + [{type: 'link', value: 'middle.com/foo/bar', noScheme: true}], + [{type: 'link', value: 'middle.com/foo/bar?baz=bux', noScheme: true}], + [{type: 'link', value: 'middle.com/foo/bar?baz=bux#hash', noScheme: true}], + [{type: 'link', value: 'start.com/foo/bar?baz=bux#hash', noScheme: true}], + [{type: 'link', value: 'end.com/foo/bar?baz=bux#hash', noScheme: true}], + [ + {type: 'link', value: 'newline1.com', noScheme: true}, + {type: 'link', value: 'newline2.com', noScheme: true}, + ], + [], + [], + [], + [], + [], + [], + [ + { + type: 'link', + value: + 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', + }, + ], + [ + { + type: 'link', + value: + 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', + }, + ], + [ + {type: 'link', value: 'https://foo.com'}, + {type: 'link', value: 'https://bar.com/whatever'}, + {type: 'link', value: 'https://baz.com'}, + ], + [ + {type: 'link', value: 'https://foo.com'}, + {type: 'link', value: 'https://bar.com/whatever'}, + {type: 'link', value: 'https://baz.com'}, + ], + [{type: 'link', value: 'https://foo.com'}], + [{type: 'link', value: 'https://foo.com/thing_(cool)'}], + ] + it('correctly handles a set of text inputs', () => { + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i] + const result = extractEntities(input, knownHandles) + if (!outputs[i].length) { + expect(result).toBeFalsy() + } else if (outputs[i].length && !result) { + expect(result).toBeTruthy() + } else if (result) { + expect(result.length).toBe(outputs[i].length) + for (let j = 0; j < outputs[i].length; j++) { + expect(result[j].type).toEqual(outputs[i][j].type) + if (outputs[i][j].noScheme) { + expect(result[j].value).toEqual(`https://${outputs[i][j].value}`) + } else { + expect(result[j].value).toEqual(outputs[i][j].value) + } + if (outputs[i]?.[j].type === 'mention') { + expect( + input.slice(result[j].index.start, result[j].index.end), + ).toBe(`@${result[j].value}`) + } else { + if (!outputs[i]?.[j].noScheme) { + expect( + input.slice(result[j].index.start, result[j].index.end), + ).toBe(result[j].value) + } else { + expect( + input.slice(result[j].index.start, result[j].index.end), + ).toBe(result[j].value.slice('https://'.length)) + } + } + } + } + } + }) +}) + +describe('detectLinkables', () => { + const inputs = [ + 'no linkable', + '@start middle end', + 'start @middle end', + 'start middle @end', + '@start @middle @end', + '@full123.test-of-chars', + 'not@right', + '@bad!@#$chars', + '@newline1\n@newline2', + 'parenthetical (@handle)', + 'start https://middle.com end', + 'start https://middle.com/foo/bar end', + 'start https://middle.com/foo/bar?baz=bux end', + 'start https://middle.com/foo/bar?baz=bux#hash end', + 'https://start.com/foo/bar?baz=bux#hash middle end', + 'start middle https://end.com/foo/bar?baz=bux#hash', + 'https://newline1.com\nhttps://newline2.com', + 'start middle.com end', + 'start middle.com/foo/bar end', + 'start middle.com/foo/bar?baz=bux end', + 'start middle.com/foo/bar?baz=bux#hash end', + 'start.com/foo/bar?baz=bux#hash middle end', + 'start middle end.com/foo/bar?baz=bux#hash', + 'newline1.com\nnewline2.com', + 'not.. a..url ..here', + 'e.g.', + 'e.g. real.com fake.notreal', + 'something-cool.jpg', + 'website.com.jpg', + 'e.g./foo', + 'website.com.jpg/foo', + 'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', + 'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/ ', + 'https://foo.com https://bar.com/whatever https://baz.com', + 'punctuation https://foo.com, https://bar.com/whatever; https://baz.com.', + 'parenthentical (https://foo.com)', + 'except for https://foo.com/thing_(cool)', + ] + const outputs = [ + ['no linkable'], + [{link: '@start'}, ' middle end'], + ['start ', {link: '@middle'}, ' end'], + ['start middle ', {link: '@end'}], + [{link: '@start'}, ' ', {link: '@middle'}, ' ', {link: '@end'}], + [{link: '@full123.test-of-chars'}], + ['not@right'], + [{link: '@bad'}, '!@#$chars'], + [{link: '@newline1'}, '\n', {link: '@newline2'}], + ['parenthetical (', {link: '@handle'}, ')'], + ['start ', {link: 'https://middle.com'}, ' end'], + ['start ', {link: 'https://middle.com/foo/bar'}, ' end'], + ['start ', {link: 'https://middle.com/foo/bar?baz=bux'}, ' end'], + ['start ', {link: 'https://middle.com/foo/bar?baz=bux#hash'}, ' end'], + [{link: 'https://start.com/foo/bar?baz=bux#hash'}, ' middle end'], + ['start middle ', {link: 'https://end.com/foo/bar?baz=bux#hash'}], + [{link: 'https://newline1.com'}, '\n', {link: 'https://newline2.com'}], + ['start ', {link: 'middle.com'}, ' end'], + ['start ', {link: 'middle.com/foo/bar'}, ' end'], + ['start ', {link: 'middle.com/foo/bar?baz=bux'}, ' end'], + ['start ', {link: 'middle.com/foo/bar?baz=bux#hash'}, ' end'], + [{link: 'start.com/foo/bar?baz=bux#hash'}, ' middle end'], + ['start middle ', {link: 'end.com/foo/bar?baz=bux#hash'}], + [{link: 'newline1.com'}, '\n', {link: 'newline2.com'}], + ['not.. a..url ..here'], + ['e.g.'], + ['e.g. ', {link: 'real.com'}, ' fake.notreal'], + ['something-cool.jpg'], + ['website.com.jpg'], + ['e.g./foo'], + ['website.com.jpg/foo'], + [ + 'Classic article ', + { + link: 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', + }, + ], + [ + 'Classic article ', + { + link: 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', + }, + ' ', + ], + [ + {link: 'https://foo.com'}, + ' ', + {link: 'https://bar.com/whatever'}, + ' ', + {link: 'https://baz.com'}, + ], + [ + 'punctuation ', + {link: 'https://foo.com'}, + ', ', + {link: 'https://bar.com/whatever'}, + '; ', + {link: 'https://baz.com'}, + '.', + ], + ['parenthentical (', {link: 'https://foo.com'}, ')'], + ['except for ', {link: 'https://foo.com/thing_(cool)'}], + ] + it('correctly handles a set of text inputs', () => { + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i] + const output = detectLinkables(input) + expect(output).toEqual(outputs[i]) + } + }) +}) + +describe('extractHtmlMeta', () => { + const inputs = [ + '', + 'nothing', + '<title>title</title>', + '<title> aSd!@#AC </title>', + '<title>\n title\n </title>', + '<meta name="title" content="meta title">', + '<meta name="description" content="meta description">', + '<meta property="og:title" content="og title">', + '<meta property="og:description" content="og description">', + '<meta property="og:image" content="https://ogimage.com/foo.png">', + '<meta property="twitter:title" content="twitter title">', + '<meta property="twitter:description" content="twitter description">', + '<meta property="twitter:image" content="https://twitterimage.com/foo.png">', + '<meta\n name="title"\n content="meta title"\n>', + ] + const outputs = [ + {}, + {}, + {title: 'title'}, + {title: 'aSd!@#AC'}, + {title: 'title'}, + {title: 'meta title'}, + {description: 'meta description'}, + {title: 'og title'}, + {description: 'og description'}, + {image: 'https://ogimage.com/foo.png'}, + {title: 'twitter title'}, + {description: 'twitter description'}, + {image: 'https://twitterimage.com/foo.png'}, + {title: 'meta title'}, + ] + it('correctly handles a set of text inputs', () => { + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i] + const output = extractHtmlMeta(input) + expect(output).toEqual(outputs[i]) + } + }) +}) + +describe('pluralize', () => { + const inputs: [number, string, string?][] = [ + [1, 'follower'], + [1, 'member'], + [100, 'post'], + [1000, 'repost'], + [10000, 'upvote'], + [100000, 'other'], + [2, 'man', 'men'], + ] + const outputs = [ + 'follower', + 'member', + 'posts', + 'reposts', + 'upvotes', + 'others', + 'men', + ] + + it('correctly pluralizes a set of words', () => { + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i] + const output = pluralize(...input) + expect(output).toEqual(outputs[i]) + } + }) +}) + +describe('makeRecordUri', () => { + const inputs: [string, string, string][] = [ + ['alice.test', 'app.bsky.feed.post', '3jk7x4irgv52r'], + ] + const outputs = ['at://alice.test/app.bsky.feed.post/3jk7x4irgv52r'] + + it('correctly builds a record URI', () => { + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i] + const result = makeRecordUri(...input) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('ago', () => { + const inputs = [ + 1671461038, + '04 Dec 1995 00:12:00 GMT', + new Date(), + new Date().setMinutes(new Date().getMinutes() - 10), + new Date().setHours(new Date().getHours() - 1), + new Date().setDate(new Date().getDate() - 1), + new Date().setMonth(new Date().getMonth() - 1), + ] + const outputs = [ + new Date(1671461038).toLocaleDateString(), + new Date('04 Dec 1995 00:12:00 GMT').toLocaleDateString(), + '0s', + '10m', + '1h', + '1d', + '1mo', + ] + + it('correctly calculates how much time passed, in a string', () => { + for (let i = 0; i < inputs.length; i++) { + const result = ago(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('makeValidHandle', () => { + const inputs = [ + 'test-handle-123', + 'test!"#$%&/()=?_', + 'this-handle-should-be-too-big', + ] + const outputs = ['test-handle-123', 'test', 'this-handle-should-b'] + + it('correctly parses and corrects handles', () => { + for (let i = 0; i < inputs.length; i++) { + const result = makeValidHandle(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('createFullHandle', () => { + const inputs: [string, string][] = [ + ['test-handle-123', 'test'], + ['.test.handle', 'test.test.'], + ['test.handle.', '.test.test'], + ] + const outputs = [ + 'test-handle-123.test', + '.test.handle.test.test.', + 'test.handle.test.test', + ] + + it('correctly parses and corrects handles', () => { + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i] + const result = createFullHandle(...input) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('enforceLen', () => { + const inputs: [string, number][] = [ + ['Hello World!', 5], + ['Hello World!', 20], + ['', 5], + ] + const outputs = ['Hello', 'Hello World!', ''] + + it('correctly enforces defined length on a given string', () => { + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i] + const result = enforceLen(...input) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('cleanError', () => { + const inputs = [ + 'TypeError: Network request failed', + 'Error: Aborted', + 'Error: TypeError "x" is not a function', + 'Error: SyntaxError unexpected token "export"', + 'Some other error', + ] + const outputs = [ + 'Unable to connect. Please check your internet connection and try again.', + 'Unable to connect. Please check your internet connection and try again.', + 'TypeError "x" is not a function', + 'SyntaxError unexpected token "export"', + 'Some other error', + ] + + it('removes extra content from error message', () => { + for (let i = 0; i < inputs.length; i++) { + const result = cleanError(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('toNiceDomain', () => { + const inputs = [ + 'https://example.com/index.html', + 'https://bsky.app', + 'https://bsky.social', + '#123123123', + ] + const outputs = ['example.com', 'bsky.app', 'Bluesky Social', '#123123123'] + + it("displays the url's host in a easily readable manner", () => { + for (let i = 0; i < inputs.length; i++) { + const result = toNiceDomain(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('toShortUrl', () => { + const inputs = [ + 'https://bsky.app', + 'https://bsky.app/3jk7x4irgv52r', + 'https://bsky.app/3jk7x4irgv52r2313y182h9', + ] + const outputs = [ + 'bsky.app', + 'bsky.app/3jk7x4irgv52r', + 'bsky.app/3jk7x4irgv52r2313y...', + ] + + it('shortens the url', () => { + for (let i = 0; i < inputs.length; i++) { + const result = toShortUrl(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('toShareUrl', () => { + const inputs = ['https://bsky.app', '/3jk7x4irgv52r', 'item/test/123'] + const outputs = [ + 'https://bsky.app', + 'https://bsky.app/3jk7x4irgv52r', + 'https://bsky.app/item/test/123', + ] + + it('appends https, when not present', () => { + for (let i = 0; i < inputs.length; i++) { + const result = toShareUrl(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) |