Skip to content
← Public packages

@danj/hey-email

HEY.com email for Kody: search threads, read messages, download PDF attachments, and write drafts. Sending is barred until you allow it.

test/paper-trail.test.js

91 lines · 3.0 KB · JavaScript
Raw
import assert from 'node:assert/strict'
import { afterEach, beforeEach, test } from 'node:test'

import moveToPaperTrail from '../src/paper-trail.js'
import { HEY, installFetch, jsonResponse, resetKodySecrets } from './helpers.mjs'

// Fixture only: the Logos weekly newsletter thread. Never a live app.hey.com call.
const LOGOS_TOPIC_ID = 2153822589
const TRAILBOX_ID = 33
const ENTRY_ID = 8001

const BOXES = [
  { id: 11, kind: 'imbox', name: 'Imbox' },
  { id: 22, kind: 'feedbox', name: 'The Feed' },
  { id: TRAILBOX_ID, kind: 'trailbox', name: 'Paper Trail' },
]

let fixture

beforeEach(() => {
  resetKodySecrets()
  fixture = installFetch(async (url, init) => {
    const method = String(init.method || 'GET').toUpperCase()
    const handler = fixture.routes.get(`${method} ${url}`)
    if (handler) return handler(url, init)
    throw new Error(`unexpected ${method} ${url}`)
  })
  fixture.routes = new Map()
})

afterEach(() => {
  fixture?.restore()
})

function on(method, url, handler) {
  fixture.routes.set(`${method} ${url}`, handler)
}

function writes() {
  return fixture.requests.filter((row) => row.method !== 'GET')
}

function routeBoxes(boxes = BOXES) {
  on('GET', `${HEY}/boxes.json`, () => jsonResponse(200, boxes))
}

function routeMove(topicId = LOGOS_TOPIC_ID) {
  on('POST', `${HEY}/topics/${topicId}/moves.json`, () => new Response(null, { status: 204 }))
}

test('moveToPaperTrail posts the single-topic MoveTopic body to the Paper Trail box', async () => {
  routeBoxes()
  routeMove()
  const moved = await moveToPaperTrail({ topicId: LOGOS_TOPIC_ID })
  const [post] = writes()
  assert.equal(post.method, 'POST')
  assert.equal(post.url, `${HEY}/topics/${LOGOS_TOPIC_ID}/moves.json`)
  assert.equal(post.headers['content-type'], 'application/json')
  assert.deepEqual(JSON.parse(post.body), { box_id: TRAILBOX_ID })
  assert.equal(moved.topicId, LOGOS_TOPIC_ID)
  assert.equal(moved.boxId, TRAILBOX_ID)
  assert.equal(moved.status, 204)
  assert.equal(moved.url, `${HEY}/topics/${LOGOS_TOPIC_ID}`)
  assert.equal(writes().length, 1)
  assert.equal(
    fixture.requests.some((row) => /clearance|contacts|postings\/moves|designation/i.test(row.url)),
    false,
  )
})

test('moveToPaperTrail with entryId reads the message topic then posts the same single-topic move', async () => {
  on('GET', `${HEY}/messages/${ENTRY_ID}.json`, () =>
    jsonResponse(200, { id: ENTRY_ID, topic_id: LOGOS_TOPIC_ID, subject: 'New resources are coming soon to Logos' }),
  )
  routeBoxes()
  routeMove()
  await moveToPaperTrail({ entryId: ENTRY_ID })
  const [post] = writes()
  assert.equal(post.method, 'POST')
  assert.equal(post.url, `${HEY}/topics/${LOGOS_TOPIC_ID}/moves.json`)
  assert.deepEqual(JSON.parse(post.body), { box_id: TRAILBOX_ID })
  assert.equal(
    fixture.requests.some((row) => /clearance|contacts|postings\/moves/i.test(row.url)),
    false,
  )
})

test('moveToPaperTrail throws before any request without topicId or entryId', async () => {
  await assert.rejects(() => moveToPaperTrail({}), /topicId or entryId is required/)
  assert.equal(fixture.requests.length, 0)
})