Skip to content
← Public packages

@kentcdodds/friction-log

Qualify and file friction papercuts to GitHub (any owner/repo) or wake Patch for Kody packages; daily sweep of kody-hq/kody friction issues.

FollowFork

src/shared.test.ts

136 lines · 4.7 KB · TypeScript
Raw
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import { agentModel, buildFrictionBody, denverDayKey, isSameFrictionBody, normalizeFrictionTitle, reuseCommentSkipReason, sanitizeForPrompt, skippedLabel, skippedLabelColor, skippedLabelDescription } from './shared.ts'

describe('agentModel', () => {
	it('uses the default high-effort Cursor Grok 4.6 variant', () => {
		assert.deepEqual(agentModel, {
			id: 'grok-4.6',
			params: [
				{ id: 'effort', value: 'high' },
				{ id: 'fast', value: 'true' },
			],
		})
	})
})

describe('denverDayKey', () => {
	it('formats a Denver calendar day as YYYY-MM-DD', () => {
		const key = denverDayKey(new Date('2026-08-21T09:00:00.000Z'))
		assert.equal(key, '2026-08-21')
		const late = denverDayKey(new Date('2026-08-21T06:30:00.000Z'))
		assert.equal(late, '2026-08-21')
		const previous = denverDayKey(new Date('2026-08-21T05:59:00.000Z'))
		assert.equal(previous, '2026-08-20')
	})
})

describe('sanitizeForPrompt', () => {
	it('neutralizes backticks and angle quotes', () => {
		assert.equal(sanitizeForPrompt('run `rm` «now»'), 'run ˋrmˋ <now>')
	})

	it('defuses Kody secret placeholders quoted in untrusted text', () => {
		const out = sanitizeForPrompt(
			'Authorization: Bearer {{secret:cloudflarePagesApiToken}} and {{ SECRET:other|scope=user }}',
		)
		assert.doesNotMatch(out, /\{\{\s*secret\s*:/i)
		assert.match(out, /\{ \{secret:cloudflarePagesApiToken\}\}/)
	})
})

describe('skippedLabel', () => {
	it('is a GitHub label distinct from friction', () => {
		assert.equal(skippedLabel, 'friction-skipped')
		assert.equal(skippedLabelColor, '6B5D52')
		assert.match(skippedLabelDescription, /until this label is removed/)
	})
})

describe('normalizeFrictionTitle', () => {
	it('prefixes Friction: once', () => {
		assert.equal(normalizeFrictionTitle('login hangs'), 'Friction: login hangs')
		assert.equal(normalizeFrictionTitle('Friction: login hangs'), 'Friction: login hangs')
		assert.equal(normalizeFrictionTitle('friction: login hangs'), 'Friction: login hangs')
	})
})

describe('buildFrictionBody', () => {
	it('uses an explicit body when provided', () => {
		assert.equal(buildFrictionBody({ body: 'already written' }), 'already written')
	})

	it('joins structured sections', () => {
		const body = buildFrictionBody({
			whatHappened: 'pre-push hung',
			whatYouWanted: 'push completes',
			preliminaryInvestigation: 'Checked husky hooks and the pre-push script.',
		})
		assert.match(body, /## What happened/)
		assert.match(body, /pre-push hung/)
		assert.match(body, /## What you wanted/)
		assert.match(body, /## Preliminary investigation/)
		assert.match(body, /husky hooks/)
	})

	it('includes relevant files only when provided', () => {
		const withFiles = buildFrictionBody({
			whatHappened: 'lint failed',
			preliminaryInvestigation: 'Opened the lint config and one failing file.',
			relevantFiles: ['tools/lint.ts', 'package.json', 'tools/lint.ts', '  '],
		})
		assert.match(withFiles, /Relevant files:/)
		assert.match(withFiles, /`tools\/lint\.ts`/)
		assert.match(withFiles, /`package\.json`/)
		assert.equal((withFiles.match(/tools\/lint\.ts/g) || []).length, 1)

		const withoutFiles = buildFrictionBody({
			whatHappened: 'lint failed',
			preliminaryInvestigation: 'No specific path stood out yet.',
		})
		assert.match(withoutFiles, /## Preliminary investigation/)
		assert.doesNotMatch(withoutFiles, /Relevant files:/)
	})
})

describe('isSameFrictionBody', () => {
	const body = buildFrictionBody({
		whatHappened: 'nx exited 1',
		whatYouWanted: 'degrade to local cache',
		preliminaryInvestigation: 'run-nx only tolerates transport failures',
		relevantFiles: ['tools/run-nx.ts'],
	})
	it('matches an identical re-filing, ignoring whitespace and CRLF', () => {
		assert.equal(isSameFrictionBody(body, body), true)
		assert.equal(
			isSameFrictionBody(body, `${body.replace(/\n/g, '\r\n')}  \n`),
			true,
		)
	})
	it('does not match new information or empty bodies', () => {
		assert.equal(isSameFrictionBody(`${body}\n\nAlso on Windows.`, body), false)
		assert.equal(isSameFrictionBody('', ''), false)
		assert.equal(isSameFrictionBody(body, null), false)
	})
})

describe('reuseCommentSkipReason', () => {
	it('skips only when disabled, empty, or identical to the issue', () => {
		assert.equal(
			reuseCommentSkipReason({ commentOnReuse: true, body: 'new', sameBodyAsExisting: false }),
			undefined,
		)
		assert.equal(
			reuseCommentSkipReason({ commentOnReuse: true, body: 'same', sameBodyAsExisting: true }),
			'same-as-issue-body',
		)
		assert.equal(
			reuseCommentSkipReason({ commentOnReuse: false, body: 'new', sameBodyAsExisting: false }),
			'disabled',
		)
		assert.equal(
			reuseCommentSkipReason({ commentOnReuse: true, body: '  ', sameBodyAsExisting: false }),
			'empty-body',
		)
	})
})