OverviewFilesCommitsIssuesDocsReleasesPeers

codetree / test / location.test.js

94 lines · javascript ref:
import { test } from 'brittle'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
import { scan } from '../lib/scanner.js'
import {
  parseLocation, locationToUrl, otherSurface, splitFilePath, joinFilePath
} from '../lib/floor/location.js'

const HERE = dirname(fileURLToPath(import.meta.url))
const WORKSPACE = resolve(HERE, 'fixtures/workspace')

// One location model for both surfaces. The SPA's PATH scheme is canonical
// because it is the one with existing deep links; the floor adopts it under a
// /floor prefix and the symbol rung extends it.

test('location: the canonical SPA scheme round-trips', (t) => {
  const cases = [
    ['/', { surface: 'spa', kind: 'system' }],
    ['/module/hyper-overlay', { surface: 'spa', kind: 'module', module: 'hyper-overlay' }],
    ['/module/hyper-overlay/file/lib/tree.js',
      { surface: 'spa', kind: 'file', module: 'hyper-overlay', file: 'lib/tree.js' }],
    ['/path/hyper-fleeky/codetree', { surface: 'spa', kind: 'path', path: ['hyper-fleeky', 'codetree'] }]
  ]
  for (const [url, expected] of cases) {
    const loc = parseLocation(url)
    for (const k of Object.keys(expected)) t.alike(loc[k], expected[k], url + ' -> ' + k)
    t.is(locationToUrl(loc), url, url + ' round-trips')
  }
})

test('location: the symbol rung extends the same scheme', (t) => {
  const url = '/module/codetree/file/lib/floor/cards.js/symbol/buildFileLevel'
  const loc = parseLocation(url)

  t.is(loc.kind, 'symbol', 'a symbol location')
  t.is(loc.module, 'codetree', 'module')
  t.is(loc.file, 'lib/floor/cards.js', 'the file path keeps its own slashes')
  t.is(loc.symbol, 'buildFileLevel', 'symbol')
  t.is(locationToUrl(loc), url, 'round-trips')
})

test('location: the floor is the same place under a prefix', (t) => {
  const spa = parseLocation('/module/codetree/file/index.js')
  const floor = parseLocation('/floor/module/codetree/file/index.js')

  t.is(floor.surface, 'floor', 'surface is read from the prefix')
  t.is(spa.surface, 'spa', 'and defaults to the SPA')
  for (const k of ['kind', 'module', 'file', 'symbol']) {
    t.alike(floor[k], spa[k], 'same ' + k)
  }
  t.is(locationToUrl(floor), '/floor/module/codetree/file/index.js', 'round-trips with the prefix')
})

test('location: otherSurface is the same place on the other view', (t) => {
  const loc = parseLocation('/module/codetree/file/lib/layout.js')
  t.is(otherSurface(loc), '/floor/module/codetree/file/lib/layout.js', 'spa -> floor')

  const back = parseLocation(otherSurface(loc))
  t.is(otherSurface(back), '/module/codetree/file/lib/layout.js', 'floor -> spa')
  t.alike({ ...back, surface: 'spa' }, loc, 'and nothing else changes')
})

test('location: a base prefix is honoured on the way in and out', (t) => {
  const loc = parseLocation('/codetree/module/x', '/codetree')
  t.is(loc.kind, 'module', 'parsed under the prefix')
  t.is(locationToUrl(loc, '/codetree'), '/codetree/module/x', 'and written back with it')
})

test('location: the SPA-only views survive', (t) => {
  t.is(parseLocation('/validation').kind, 'validation', 'validation')
  t.is(parseLocation('/validation/module/x').extra.moduleName, 'x', 'with its module')
  t.is(parseLocation('/docs/spec/SYSTEM.md').extra.docPath, 'spec/SYSTEM.md', 'docs path')
  t.is(locationToUrl(parseLocation('/docs/spec/SYSTEM.md')), '/docs/spec/SYSTEM.md', 'round-trips')
  t.is(parseLocation('/suggestions/spec/x.md').kind, 'suggestions', 'suggestions')
})

test('location: nonsense is the system level, not a throw', (t) => {
  for (const url of ['', '/nope', '/module', '/module//file//', '///']) {
    const loc = parseLocation(url)
    t.ok(loc.kind, url + ' parses to something: ' + loc.kind)
  }
})

test('location: a root-relative path splits into module + file, and back', async (t) => {
  const tree = await scan(WORKSPACE, { maxDepth: 1 })

  const split = splitFilePath(tree, 'widget-store/lib/widget-store.js')
  t.is(split.module, 'widget-store', 'module found')
  t.is(split.file, 'lib/widget-store.js', 'path within it')
  t.is(joinFilePath(tree, split.module, split.file), 'widget-store/lib/widget-store.js', 'and back')

  t.alike(splitFilePath(tree, 'nope/nothing.js'), { module: null, file: null }, 'unknown is null')
})