OverviewFilesCommitsIssuesDocsReleasesPeers

codetree / test / live-store.test.js

86 lines · javascript ref:
import { test } from 'brittle'
import { writeFileSync, mkdirSync, rmSync, existsSync } from 'fs'
import { join, resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
import { LiveStore } from '../lib/live-store.js'
import { scanStream } from '../lib/scan-stream.js'
import { TreeReducer } from '../lib/reducers/tree-reducer.js'

const HERE = dirname(fileURLToPath(import.meta.url))
const FIXTURE = resolve(HERE, 'fixtures-live')

function setup () {
  if (existsSync(FIXTURE)) rmSync(FIXTURE, { recursive: true, force: true })
  mkdirSync(FIXTURE, { recursive: true })
  writeFileSync(join(FIXTURE, 'package.json'), JSON.stringify({ name: 'fixture-live', version: '0.1.0', main: 'index.js' }))
  writeFileSync(join(FIXTURE, 'index.js'), 'export const x = 1\n')
}

async function buildGraph () {
  return new Promise((resolveP, reject) => {
    const src = scanStream(FIXTURE)
    const tree = new TreeReducer().attach(src)
    src.once('scan-end', () => resolveP(tree.finalize()))
    src.once('error', reject)
  })
}

test('live-store: subscribe receives current state on attach', async (t) => {
  setup()
  const graph = await buildGraph()
  const store = new LiveStore(graph, { watch: false })
  store.seedFromGraph()

  const events = []
  store.subscribe(ev => events.push(ev.type))

  t.is(events[0], 'scan-start', 'first replayed event is scan-start')
  t.ok(events.includes('module-start'), 'module-start replayed')
  t.ok(events.includes('file-discovered'), 'file-discovered replayed')
  t.ok(events.includes('file-parsed'), 'file-parsed replayed')
  t.is(events[events.length - 1], 'scan-end', 'last replayed event is scan-end')

  store.stop()
  rmSync(FIXTURE, { recursive: true, force: true })
})

test('live-store: late subscribers also get full state', async (t) => {
  setup()
  const graph = await buildGraph()
  const store = new LiveStore(graph, { watch: false })
  store.seedFromGraph()

  // First subscriber
  const first = []
  store.subscribe(ev => first.push(ev.type))

  // Second subscriber attaches AFTER seeding — must still get the full replay
  const second = []
  store.subscribe(ev => second.push(ev.type))

  t.is(first.length, second.length, 'both subscribers see same number of events')
  t.alike(first, second, 'event sequences match')

  store.stop()
  rmSync(FIXTURE, { recursive: true, force: true })
})

test('live-store: module-start payload uses moduleType not type for JS module flavor', async (t) => {
  setup()
  const graph = await buildGraph()
  const store = new LiveStore(graph, { watch: false })
  store.seedFromGraph()

  let modStart = null
  store.subscribe(ev => {
    if (ev.type === 'module-start' && !modStart) modStart = ev
  })

  t.ok(modStart, 'got module-start event')
  t.is(modStart.type, 'module-start', 'event type is preserved (no name collision)')
  t.ok('moduleType' in modStart, 'JS module type carried as moduleType field')

  store.stop()
  rmSync(FIXTURE, { recursive: true, force: true })
})