Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/producthunt

src/helpers.test.ts

56 lines · 2.4 KB · TypeScript
import assert from 'node:assert/strict'
import { test } from 'node:test'
import { resolveIntegrationName, resolveSecretName } from './setup.ts'
import {
	accessTokenSetupUrl,
	clampPageSize,
	clientSecretSetupUrl,
	inferOperation,
	isReadOnlyQuery,
	oauthConnectUrl,
	scopeForOperation,
} from './setup.ts'
import { todayBounds } from './today.ts'

test('todayBounds uses the Pacific Product Hunt day', () => {
	const bounds = todayBounds('America/Los_Angeles', new Date('2026-08-22T18:00:00.000Z'))
	assert.equal(bounds.day, '2026-08-22')
	assert.equal(bounds.timeZone, 'America/Los_Angeles')
	assert.ok(Date.parse(bounds.postedAfter) < Date.parse(bounds.postedBefore))
	assert.match(bounds.postedAfter, /T/)
})

test('clampPageSize stays in the Product Hunt 1-20 range', () => {
	assert.equal(clampPageSize(undefined), 10)
	assert.equal(clampPageSize(1), 1)
	assert.equal(clampPageSize(20), 20)
	assert.equal(clampPageSize(99), 20)
	assert.equal(clampPageSize(0), 1)
})

test('GraphQL mutation documents are not read-only', () => {
	assert.equal(inferOperation('query { posts { edges { node { id } } } }'), 'query')
	assert.equal(inferOperation('mutation { userFollow(input: { userId: "x" }) { user { id } } }'), 'mutation')
	assert.equal(isReadOnlyQuery('query { viewer { user { id } } }'), true)
	assert.equal(isReadOnlyQuery('mutation Foo { goalCreate(input: { title: "x" }) { goal { id } } }'), false)
	assert.equal(scopeForOperation('query'), 'public')
	assert.equal(scopeForOperation('mutation'), 'write')
})

test('setup URLs are prefilled for OAuth and secrets', () => {
	const connect = oauthConnectUrl('producthunt')
	assert.match(connect, /^https:\/\/kody\.codes\/connect\/oauth\?/)
	assert.match(connect, /provider=producthunt/)
	assert.match(connect, /scopes=public(\+|%20)private/)
	assert.match(connect, /api\.producthunt\.com/)
	assert.match(accessTokenSetupUrl(), /name=producthuntAccessToken/)
	assert.match(accessTokenSetupUrl(), /allowedHosts=api\.producthunt\.com/)
	assert.match(clientSecretSetupUrl(), /name=producthuntClientSecret/)
})

test('account aliases stay generic and unscoped to a person', () => {
	assert.equal(resolveIntegrationName({}), 'producthunt')
	assert.equal(resolveIntegrationName({ account: 'work' }), 'producthunt-work')
	assert.equal(resolveSecretName({ account: 'work' }), 'producthuntAccessToken-work')
	assert.equal(resolveSecretName({}), 'producthuntAccessToken')
})