mirror of
https://github.com/stablyai/orca.git
synced 2026-09-25 16:02:38 +00:00
test(mobile): pin Project host routing to the declared method, not the identifier prefix
The guard matched `githubProject*.request(` sites, so an operation renamed off that prefix left the prefix match empty and the host could go with the rename: renaming `githubProjectFieldUpdate` to `projectFieldUpdate` at its definition and its one call site and deleting `host: activeGitHubProjectHost` from the `github.project.updateItemField` request kept all three tests and `tsc` green, and `host` is optional in the params type so nothing else caught it. Derive the list from the board module by the method each operation declares instead, and scan every product file under `mobile/src` rather than a hand-listed eight, so a site that moves stays covered. Coverage goes from 13 matched sites to 17 across all 16 declared operations, because the old regex also missed the `op\n .request(` form four of them use. An operation that stops being requested at all now fails too. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { readFileSync, readdirSync } from 'node:fs'
|
||||
import { join, relative, resolve } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const readSource = (path: string): string => readFileSync(new URL(path, import.meta.url), 'utf8')
|
||||
const productRoot = resolve(import.meta.dirname, '..')
|
||||
const source = [
|
||||
readSource('./use-mobile-tasks-project-loading-actions.tsx'),
|
||||
readSource('./use-mobile-tasks-project-workspace-comment-actions.tsx'),
|
||||
@@ -25,18 +27,52 @@ function sendsMethod(operations: string, operation: string, method: string): boo
|
||||
return offset !== -1 && operations.slice(offset, offset + 400).includes(`method: '${method}'`)
|
||||
}
|
||||
|
||||
/** Every product file that could send a board request. Recorder fixtures are not call sites. */
|
||||
function productSources(directory: string): string[] {
|
||||
return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
||||
const path = join(directory, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
return entry.name === 'test-support' ? [] : productSources(path)
|
||||
}
|
||||
return /\.tsx?$/.test(entry.name) && !entry.name.includes('.test.') ? [path] : []
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* The board's operations by the method each declares, never by the `githubProject` identifier
|
||||
* prefix: renaming an operation off that prefix takes it out of a prefix match, so the rename can
|
||||
* delete the host with this test still green. The method it sends is what routing follows.
|
||||
*/
|
||||
function projectOperations(): string[] {
|
||||
const declarations = [...boardOperations.matchAll(/export const (\w+) =/g)]
|
||||
return declarations
|
||||
.filter((declaration, index) =>
|
||||
boardOperations
|
||||
.slice(declaration.index, declarations[index + 1]?.index ?? boardOperations.length)
|
||||
.includes("method: 'github.project.")
|
||||
)
|
||||
.map((declaration) => declaration[1]!)
|
||||
}
|
||||
|
||||
describe('mobile GitHub Project host routing boundary', () => {
|
||||
it('host-qualifies every Project RPC request', () => {
|
||||
const calls = [...source.matchAll(/\b(githubProject[A-Za-z]+)\.request\(/g)]
|
||||
expect(calls.length).toBeGreaterThan(10)
|
||||
for (const call of calls) {
|
||||
const request = source.slice(call.index, call.index + 700)
|
||||
expect(request, `${call[1]} must carry a host`).toMatch(/\bhost\s*:/)
|
||||
expect(
|
||||
boardOperations.includes(`export const ${call[1]} =`),
|
||||
`${call[1]} must be a declared Project operation`
|
||||
).toBe(true)
|
||||
const operations = projectOperations()
|
||||
expect(operations.length).toBeGreaterThan(10)
|
||||
const unrouted: string[] = []
|
||||
const wired = new Set<string>()
|
||||
for (const path of productSources(productRoot)) {
|
||||
const contents = readFileSync(path, 'utf8')
|
||||
for (const operation of operations) {
|
||||
for (const call of contents.matchAll(new RegExp(`\\b${operation}\\s*\\.request\\(`, 'g'))) {
|
||||
wired.add(operation)
|
||||
if (!/\bhost\s*:/.test(contents.slice(call.index, call.index + 700))) {
|
||||
unrouted.push(`${relative(productRoot, path)} sends ${operation} with no host`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(unrouted).toEqual([])
|
||||
expect(operations.filter((operation) => !wired.has(operation))).toEqual([])
|
||||
})
|
||||
|
||||
it('pins Project-row PR actions to the row repository identity', () => {
|
||||
|
||||
Reference in New Issue
Block a user