tftsr-devops_investigation/node_modules/rgb2hex/test/rgb2hex.test.js
Shaun Arman 8839075805 feat: initial implementation of TFTSR IT Triage & RCA application
Implements Phases 1-8 of the TFTSR implementation plan.

Rust backend (Tauri 2.x, src-tauri/):
- Multi-provider AI: OpenAI-compatible, Anthropic, Gemini, Mistral, Ollama
- PII detection engine: 11 regex patterns with overlap resolution
- SQLCipher AES-256 encrypted database with 10 versioned migrations
- 28 Tauri IPC commands for triage, analysis, document, and system ops
- Ollama: hardware probe, model recommendations, pull/delete with events
- RCA and blameless post-mortem Markdown document generators
- PDF export via printpdf
- Audit log: SHA-256 hash of every external data send
- Integration stubs for Confluence, ServiceNow, Azure DevOps (v0.2)

Frontend (React 18 + TypeScript + Vite, src/):
- 9 pages: full triage workflow NewIssue→LogUpload→Triage→Resolution→RCA→Postmortem→History+Settings
- 7 components: ChatWindow, TriageProgress, PiiDiffViewer, DocEditor, HardwareReport, ModelSelector, UI primitives
- 3 Zustand stores: session, settings (persisted), history
- Type-safe tauriCommands.ts matching Rust backend types exactly
- 8 IT domain system prompts (Linux, Windows, Network, K8s, DB, Virt, HW, Obs)

DevOps:
- .woodpecker/test.yml: rustfmt, clippy, cargo test, tsc, vitest on every push
- .woodpecker/release.yml: linux/amd64 + linux/arm64 builds, Gogs release upload

Verified:
- cargo check: zero errors
- tsc --noEmit: zero errors
- vitest run: 13/13 unit tests passing

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 22:36:25 -05:00

161 lines
6.3 KiB
JavaScript

const rgb2hex = require('../index')
const typeofErrorMessage = 'color has to be type of `string`'
const invalidErrorMessage = (input) => 'given color (' + input + ') isn\'t a valid rgb or rgba color'
describe('rgb2hex should', () => {
describe('throw an error if input is not typeof string', () => {
it('[Object] {color: \'something\'}', () => {
const input = {color: 'something'}
expect(() => rgb2hex(input)).toThrow(typeofErrorMessage)
})
it('[Function] function(){}', () => {
const input = function(){}
expect(() => rgb2hex(input)).toThrow(typeofErrorMessage)
})
it('[Number] 231', () => {
const input = 231
expect(() => rgb2hex(input)).toThrow(typeofErrorMessage)
})
})
describe('throw an error if input is invalid', () => {
it('notacolor', () => {
const input = 'notacolor'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
})
it('rgba(100, 100)', () => {
const input = 'rgb(100, 100)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
})
it('rgba(100, 10a0, 200, 300)', () => {
const input = 'rgba(100, 10a0, 200, 300)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
})
it('rgba(23, 54, 4, -.33)', () => {
const input = 'rgba(23, 54, 4, -.33)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
})
})
it('return input if it is already a hex color', () => {
const input = '#ffffff'
const parsedValue = rgb2hex(input)
expect(parsedValue).toHaveProperty('hex')
expect(parsedValue).toHaveProperty('alpha')
expect(typeof parsedValue.hex).toEqual('string')
expect(parsedValue.hex).toEqual('#ffffff')
expect(typeof parsedValue.alpha).toEqual('number')
expect(parsedValue.alpha).toEqual(1)
})
describe('parse input properly', () => {
it('converting rgb(210,43,255)', () => {
const input = 'rgb(210,43,255)'
const parsedValue = rgb2hex(input)
expect(parsedValue).toHaveProperty('hex')
expect(parsedValue).toHaveProperty('alpha')
expect(typeof parsedValue.hex).toEqual('string')
expect(parsedValue.hex).toEqual('#d22bff')
expect(typeof parsedValue.alpha).toEqual('number')
expect(parsedValue.alpha).toEqual(1)
})
it('converting rgba(12,173,22,.67313)', () => {
const input = 'rgba(12,173,22,.67313)'
const parsedValue = rgb2hex(input)
expect(parsedValue).toHaveProperty('hex')
expect(parsedValue).toHaveProperty('alpha')
expect(typeof parsedValue.hex).toEqual('string')
expect(parsedValue.hex).toEqual('#0cad16')
expect(typeof parsedValue.alpha).toEqual('number')
expect(parsedValue.alpha).toEqual(0.67)
})
it('by limiting alpha value to 1', () => {
const input = 'rgba(236,68,44,1)'
expect(rgb2hex(input).alpha).not.toBeGreaterThan(1)
})
it('by not accepting to big values', () => {
let input = 'rgba(1123, 54, 4, 0.33)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
input = 'rgba(113, 1154, 4, 0.33)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
input = 'rgba(113, 154, 1114, 0.33)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
input = 'rgba(113, 54, 4, 2.33)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
input = 'rgbaaaaaa(113, 54, 4, .33)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
input = 'rgba(12,173,22,1.67)'
expect(() => rgb2hex(input)).toThrow(invalidErrorMessage(input))
})
it('transparent color', () => {
const input = 'rgba(0, 0, 0, 0)'
expect(rgb2hex(input).alpha).toBe(0)
expect(rgb2hex(input).hex).toBe('#000000')
})
it('double digit alpha values', () => {
const input = 'rgba(0, 0, 0, 1.00)'
expect(rgb2hex(input).alpha).toBe(1)
expect(rgb2hex(input).hex).toBe('#000000')
})
})
describe('not care about', () => {
it('rgb or rgba prefix', () => {
const rgb = 'rgb(0, 0, 0)'
const rgba = 'rgba(0, 0, 0)'
expect(rgb2hex(rgb).hex).toEqual(rgb2hex(rgba).hex)
})
it('spaces between color numbers', () => {
const rgbWithSpaces = 'rgb(0, 0, 0)'
const rgbaWithoutSpaces = 'rgba(0,0,0)'
expect(rgb2hex(rgbWithSpaces).hex).toEqual(rgb2hex(rgbaWithoutSpaces).hex)
})
it('if alpha value starts with `.` or with `0`', () => {
const rgbaAlphaStartsWithDot = 'rgba(213,12,4,.45)'
const rgbaAlphaStartsWithZero = 'rgba(213,12,4,0.45)'
expect(rgb2hex(rgbaAlphaStartsWithDot).alpha).toEqual(rgb2hex(rgbaAlphaStartsWithZero).alpha)
})
it('optional terminating semicolon', () => {
const rgbWithTerminatingSemicolon = 'rgb(0,0,0);'
const rgbWithoutTerminatingSemicolon = 'rgb(0,0,0)'
expect(rgb2hex(rgbWithTerminatingSemicolon).hex).toEqual(rgb2hex(rgbWithoutTerminatingSemicolon).hex)
})
it('stuff that is appended', () => {
expect(rgb2hex('rgb(0,0,0)0px0px8px').hex).toEqual(rgb2hex('rgb(0,0,0)').hex)
expect(rgb2hex('rgb(0,0,0)solid2px').hex).toEqual(rgb2hex('rgb(0,0,0)').hex)
})
it('stuff that is prepended', () => {
expect(rgb2hex('0px0px8pxrgb(0,0,0)').hex).toEqual(rgb2hex('rgb(0,0,0)').hex)
expect(rgb2hex('solid2pxrgb(0,0,0)').hex).toEqual(rgb2hex('rgb(0,0,0)').hex)
})
it('stuff that is prepended and appended', () => {
const url = 'https://foo.bar.com/123.abc.456'
const values = `url("${url}")no-repeatscroll0%0%/100%padding-boxborder-box`
expect(rgb2hex(`${values}rgb(226,230,233)${values}`).hex)
expect(rgb2hex(`${values}rgba(226,230,233,0.4)${values}`).hex)
})
})
})