Skip to content

Commit

Permalink
Extend tests for utils
Browse files Browse the repository at this point in the history
  • Loading branch information
chrispuska committed Jan 6, 2024
1 parent 71c183f commit 184cf1c
Show file tree
Hide file tree
Showing 29 changed files with 858 additions and 264 deletions.
37 changes: 33 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,37 @@
.cache
.DS_Store
.env
.env.development.local
.env.local
.env.test
.eslintcache
.git
.next
.node_repl_history
.nova
.now
.npm
.sentryclirc
.tmp
.turbo
.vercel
.vscode
out
.yarn
.yarn-integrity
*.lcov
*.log
*.pid
*.pid.lock
*.seed
*.tsbuildinfo
# next-env.d.ts
coverage
dist
dist-demo
node_modules
yarn-error.log
logs
node_modules/
npm-debug.log*
pids
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
typings/
yarn-debug.log*
yarn-error.log*
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.git
.env
node_modules
1 change: 0 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"tabWidth": 2,
"useTabs": true
}
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015 Chris Puska
Copyright (c) 2015 Helios Graphics

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Fractures

Fractures is a collection of low level atomic utilities for humans that makes products more resilient, composable and scalable. Only the good parts.
Fractures is a collection of low level atomic utilities that makes products more resilient, composable and scalable. Only the good parts.

- Atomic
- Framework agnostic
Expand All @@ -14,7 +14,3 @@ Fractures is a collection of low level atomic utilities for humans that makes pr
- `@heliosgraphics/fractures` Atomic CSS.
- `@heliosgraphics/library` Types and constraints of visual spaces, no presets or definitions.
- `@heliosgraphics/utils` Helpers functions for both.

### Roadmap

- `2024` Fractures as a template repository for agents to build from.
26 changes: 16 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
{
"author": "Chris Puska <03b8@helios.graphics>",
"author": "03b8 <03b8@helios.graphics>",
"private": false,
"license": "MIT",
"version": "4.0.0-alpha-5",
"version": "4.1.0",
"scripts": {
"test": "vitest",
"test": "NODE_ENV=test vitest run",
"test:u": "NODE_ENV=test vitest run --update",
"test:watch": "NODE_ENV=test vitest",
"test:coverage": "NODE_ENV=test vitest run --coverage",
"pub:fractures": "pnpm publish --access public --filter fractures",
"pub:library": "pnpm publish --access public --filter library",
"pub:utils": "pnpm publish --access public --filter utils",
Expand All @@ -15,12 +18,15 @@
],
"dependencies": {},
"devDependencies": {
"@types/node": "^20.6.3",
"@types/react": "^18.2.22",
"eslint": "^8.50.0",
"eslint-config-next": "^13.5.2",
"prettier": "^3.0.3",
"typescript": "^5.2.2",
"vitest": "^1.1.0"
"@types/node": "latest",
"@types/react": "latest",
"@vitest/coverage-v8": "latest",
"eslint": "latest",
"eslint-config-next": "latest",
"jsdom": "latest",
"prettier": "latest",
"typescript": "latest",
"vite": "latest",
"vitest": "latest"
}
}
4 changes: 2 additions & 2 deletions packages/fractures/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@heliosgraphics/fractures",
"version": "4.0.0-alpha-5",
"type": "module",
"author": "Chris Puska <03b8@helios.graphics>",
"author": "03b8 <03b8@helios.graphics>",
"description": "Functional CSS, but only the good parts.",
"main": "dist/fractures.min.css",
"files": [
Expand Down Expand Up @@ -32,6 +32,6 @@
},
"devDependencies": {
"typescript": "^5.3.3",
"vitest": "^1.1.0"
"vitest": "^1.1.3"
}
}
8 changes: 4 additions & 4 deletions packages/library/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "@heliosgraphics/library",
"version": "4.0.0-alpha-5",
"version": "4.1.0",
"private": false,
"type": "module",
"author": "Chris Puska <03b8@helios.graphics>",
"description": "Atomic CSS Library",
"author": "03b8 <03b8@helios.graphics>",
"description": "Helios Library",
"main": "./src/index",
"devDependencies": {
"csstype": "^3.1.3"
"csstype": "latest"
}
}
2 changes: 1 addition & 1 deletion packages/library/utils/flex.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ describe('getFlexUtility', () => {
}

it('Generates without duplicated classes', () => expect(getFlexUtility(MOCK_FLEX_DUPLICATE, 'flex')).toEqual(MOCK_FLEX_DUPLICATE_CLASSES));
it('Generates with external classname', () => expect(getFlexUtility({}, 'style-01')).toEqual('flex style-01'));
it('Generates with external className', () => expect(getFlexUtility({}, 'style-01')).toEqual('flex style-01'));
});
30 changes: 30 additions & 0 deletions packages/utils/clipboard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, it, expect, vi } from 'vitest';
import { copyValue } from './clipboard'

const TEXT_STRING = 'Test text' as const;

describe('copyValue', () => {
it('copies text to the clipboard', () => {
const createElementMock: any = {
value: '',
select: vi.fn(),
remove: vi.fn(),
};

const spyCreateElement = vi.spyOn(document, 'createElement').mockImplementation(() => createElementMock);
const spyAppendChild = vi.spyOn(document.body, 'appendChild').mockImplementation(node => node);

document.execCommand = vi.fn();

copyValue(TEXT_STRING);
expect(spyCreateElement).toHaveBeenCalledWith('input');
expect(spyAppendChild).toHaveBeenCalled();
expect(document.execCommand).toHaveBeenCalledWith('copy', false);

const inputElement: HTMLInputElement = spyCreateElement.mock.results[0].value;
expect(inputElement.value).toBe(TEXT_STRING);

spyCreateElement.mockRestore();
spyAppendChild.mockRestore();
});
});
13 changes: 7 additions & 6 deletions packages/utils/clipboard.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
export const copyValue = (text: string) => {
const inp = document.createElement('input');
// copies the given value to the clipboard.
export const copyValue = (text: string): void => {
const input: HTMLInputElement = document.createElement('input');

document.body.appendChild(inp);
inp.value = text;
inp.select();
document.body.appendChild(input);
input.value = text;
input.select();
document.execCommand('copy', false);

return inp.remove();
return input.remove();
};
14 changes: 10 additions & 4 deletions packages/utils/colors.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { rgbToHex } from './colors'
import { it, describe, expect } from 'vitest';
import { rgbToHex, hexToRgb, DEFAULT_PROFILE_RGB } from './colors'

describe('colors', () => {
describe('hexToRgb', () => {
it('converts hex to rgb', () => expect(hexToRgb('#0c2c78')).toEqual([12, 44, 120]));
it('returns default for 0', () => expect(hexToRgb(<any>0)).toEqual(DEFAULT_PROFILE_RGB));
it('returns default for undefined', () => expect(hexToRgb(<any>undefined)).toEqual(DEFAULT_PROFILE_RGB));
});

describe('rgbToHex', () => {
it('converts rgb to hex', () => expect(rgbToHex(12, 44, 120)).toEqual('#0c2c78'));
it('converts strings to hex', () => expect(rgbToHex('12' as any as number, '44' as any as number, '120' as any as number)).toEqual('#ffffff'));
it('converts even with a null input to hex', () => expect(rgbToHex(null as any, 44, 120)).toEqual('#ff2c78'));
it('converts undefined to hex', () => expect(rgbToHex(12, undefined as any, 120)).toEqual('#0cff78'));
it('converts string to hex', () => expect(rgbToHex(<any>'12', <any>'44', <any>'120')).toEqual('#0c2c78'));
it('converts null to hex', () => expect(rgbToHex(<any>null, 44, 120)).toEqual('#002c78'));
it('returns undefined to hex', () => expect(rgbToHex(12, <any>undefined, 120)).toEqual('#0cff78'));
});
});
34 changes: 15 additions & 19 deletions packages/utils/colors.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { TypeRGB } from '@heliosgraphics/library/types/colors'

const DEFAULT_PROFILE_RGB: TypeRGB = [199, 201, 209];
export const DEFAULT_PROFILE_RGB: TypeRGB = [199, 201, 209] as const;

// converts a hex value to a TypeRGB.
export const hexToRgb = (hex?: string | null): TypeRGB => {
const isString: boolean = !!hex && typeof hex === 'string';
const isValid: boolean = !!hex && typeof hex === 'string'

if (!isString) return DEFAULT_PROFILE_RGB
if (!isValid) return DEFAULT_PROFILE_RGB

hex = hex!.replace(/^#/, '');

Expand All @@ -17,23 +18,18 @@ export const hexToRgb = (hex?: string | null): TypeRGB => {
return [r, g, b];
}

export const rgbToHex = (r: number = 255, g: number = 255, b: number = 255): string => {
const _toHex = (c: number): string => {
const hex = c.toString(16);
return hex.length === 1 ? '0' + hex : hex;
};
// converts an rgb value to a hex string (#0cd0cd).
export const rgbToHex = (r: number | string = 255, g: number | string = 255, b: number | string = 255): string => {
const _toHex = (c: unknown): string => {
const value = Number(c)
const isValid: boolean = isNaN(value) || value < 0 || value > 255

const isRNumber: boolean = typeof r === 'number';
const isGNumber: boolean = typeof g === 'number';
const isBNumber: boolean = typeof b === 'number';
if (isValid) return 'FF';

const RR: number = isRNumber ? r : 255;
const GG: number = isGNumber ? g : 255;
const BB: number = isBNumber ? b : 255;
const hex = value.toString(16);

const hexR: string = _toHex(RR);
const hexG: string = _toHex(GG);
const hexB: string = _toHex(BB);
return hex.length === 1 ? `0${hex}` : hex;
};

return `#${hexR}${hexG}${hexB}`;
}
return `#${_toHex(r)}${_toHex(g)}${_toHex(b)}`;
};
41 changes: 41 additions & 0 deletions packages/utils/debounce.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { debounce, type CallbackFunction } from './debounce'

describe('debounce', () => {
let callback: CallbackFunction;
let debouncedFunction: CallbackFunction;

beforeEach(() => {
vi.useFakeTimers();

callback = vi.fn();
debouncedFunction = debounce(callback, 1000);
});

afterEach(() => {
vi.useRealTimers();
});

it('calls the callback after the specified time', () => {
debouncedFunction();

vi.advanceTimersByTime(500);
expect(callback).not.toHaveBeenCalled();

vi.advanceTimersByTime(500);
expect(callback).toHaveBeenCalled();
});

it('does not call the callback if the function is called again within the wait time', () => {
debouncedFunction();
vi.advanceTimersByTime(500);

debouncedFunction();
vi.advanceTimersByTime(500);

expect(callback).not.toHaveBeenCalled();

vi.advanceTimersByTime(500);
expect(callback).toHaveBeenCalledTimes(1);
});
});
7 changes: 5 additions & 2 deletions packages/utils/debounce.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export const debounce = (callback: Function, wait: number) => {
export type CallbackFunction = (...args: Array<unknown>) => void

// debounces the function with wait time passed.
export const debounce = (callback: CallbackFunction, wait: number): CallbackFunction => {
let timeoutId: any;

return (...args: any) => {
return (...args: Array<unknown>) => {
globalThis.clearTimeout(timeoutId);

timeoutId = globalThis.setTimeout(() => {
Expand Down
7 changes: 4 additions & 3 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
{
"name": "@heliosgraphics/utils",
"version": "4.0.0-alpha-5",
"version": "4.1.0",
"private": false,
"type": "module",
"author": "Chris Puska <03b8@helios.graphics>",
"author": "03b8 <03b8@helios.graphics>",
"description": "Helios Utils",
"dependencies": {
"@heliosgraphics/library": "latest",
"uuid": "^9.0.1",
"xss": "^1.0.14"
},
"devDependencies": {
"@types/uuid": "9.0.7"
"@types/uuid": "latest"
}
}
16 changes: 7 additions & 9 deletions packages/utils/slug.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { getSlug } from "./slug";
import { it, describe, expect } from 'vitest';
import { getSlug } from "./slug";

describe('slug', () => {

describe('getSlug', () => {
// Good
it('Gets a lowercase subdomain from case 1', () => expect(getSlug('--BuRn--')).toEqual('-burn-'));
it('Gets a lowercase subdomain from case 2', () => expect(getSlug('#$%^B#uR#n-')).toEqual('burn-'));
it('Gets a nice slug for a category', () => expect(getSlug('Gaussian Blur')).toEqual('gaussian-blur'));

// Empty
it('Gets empty string if subdomain is undefined', () => expect(getSlug(undefined)).toEqual(''));
it('returns valid from string with dashes', () => expect(getSlug('--B—uRn--')).toEqual('-burn-'));
it('returns valid from special string', () => expect(getSlug('#$%^B#uR#n-')).toEqual('burn-'));
it('returns valid from parens string', () => expect(getSlug('Gaussian Blur [1](2){3}')).toEqual('gaussian-blur-123'));
it('replaces àáäâèéëêìíïîòóöôùúüûñç', () => expect(getSlug('àáäâèéëêìíïîòóöôùúüûñç')).toEqual('aaaaeeeeiiiioooouuuunc'));
it('fails silently from undefined', () => expect(getSlug(undefined)).toEqual(''));
it('fails silently from null', () => expect(getSlug(<any>null)).toEqual(''));
});
});
Loading

0 comments on commit 184cf1c

Please sign in to comment.