surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| 1 | import { describe, expect, mock, test, tier } from 'claude-code/testing' |
| 2 | |
| 3 | import Hooks from '../hooks' |
| 4 | import Fixtures from './fixtures' |
| 5 | |
| 6 | tier('builtin') |
| 7 | |
| 8 | const refusal = `HooksError: reaching: $.telemetry.log: ${Hooks.REFUSED.deny}` |
| 9 | |
| 10 | describe('gate', () => { |
| 11 | test( |
| 12 | 'the table an engine.create step is handed serves no one above either', |
| 13 | { plugins: [Fixtures.recording, Fixtures.reaching] }, |
| 14 | async ($, on) => { |
| 15 | mock.env(on, Fixtures.SENDING_ENV) |
| 16 | |
| 17 | const session = Fixtures.firstPartySession(on) |
| 18 | |
| 19 | on('tool.call', () => ({ result: 'read' })) |
| 20 | |
| 21 | await $.session.start(Fixtures.STARTED) |
| 22 | await session.clock.advance(1) |
| 23 | await $.tool.call(Fixtures.READ_TOOL) |
| 24 | |
| 25 | const during = (await $.command.run(Fixtures.typed('reach', {}))).text |
| 26 | |
| 27 | await $.command.run(Fixtures.record(Fixtures.surveyAnswer())) |
| 28 | await session.clock.advance(Hooks.BATCH_WINDOW_MS) |
| 29 | |
| 30 | expect({ |
| 31 | isServedDuringCreate: during === 'served', |
| 32 | later: session.lines.filter(line => !line.startsWith('telemetry: ')), |
| 33 | rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf), |
| 34 | }).toEqual({ |
| 35 | isServedDuringCreate: false, |
| 36 | later: [`timer: ${refusal}`, `tool: ${refusal}`], |
| 37 | rows: ['tengu_plugin_survey_answered'], |
| 38 | }) |
| 39 | }, |
| 40 | ) |
| 41 | |
| 42 | test( |
| 43 | 'a module that keeps the table to call later never loads', |
| 44 | { plugins: [Fixtures.holding] }, |
| 45 | async ($, on) => { |
| 46 | mock.env(on, Fixtures.SENDING_ENV) |
| 47 | |
| 48 | const session = Fixtures.firstPartySession(on) |
| 49 | |
| 50 | const held = await $.command |
| 51 | .run(Fixtures.typed('hold', {})) |
| 52 | .then(result => result.text, String) |
| 53 | |
| 54 | await session.clock.advance(Hooks.BATCH_WINDOW_MS) |
| 55 | |
| 56 | expect({ |
| 57 | isLoaded: !String(held).includes('did not load'), |
| 58 | posts: session.posts, |
| 59 | }).toEqual({ isLoaded: false, posts: [] }) |
| 60 | }, |
| 61 | ) |
| 62 | |
| 63 | test( |
| 64 | "a hook above on the collector's stream renames no row, sends none", |
| 65 | { plugins: [Fixtures.recording, Fixtures.meddling] }, |
| 66 | async ($, on) => { |
| 67 | mock.env(on, Fixtures.SENDING_ENV) |
| 68 | |
| 69 | const session = Fixtures.firstPartySession(on) |
| 70 | const own = (await $.command.run(Fixtures.typed('meddle', {}))).text |
| 71 | |
| 72 | await $.command.run(Fixtures.record(Fixtures.surveyAnswer())) |
| 73 | await session.clock.advance(Hooks.BATCH_WINDOW_MS) |
| 74 | |
| 75 | expect({ |
| 76 | own, |
| 77 | rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf), |
| 78 | }).toEqual({ |
| 79 | own: `HooksError: meddling: $.telemetry.log: ${Hooks.REFUSED.deny}`, |
| 80 | rows: ['tengu_plugin_survey_answered'], |
| 81 | }) |
| 82 | }, |
| 83 | ) |
| 84 | |
| 85 | test( |
| 86 | "a hook above that swallows the collector's stream stops no row", |
| 87 | { plugins: [Fixtures.recording, Fixtures.swallowing] }, |
| 88 | async ($, on) => { |
| 89 | mock.env(on, Fixtures.SENDING_ENV) |
| 90 | |
| 91 | const session = Fixtures.firstPartySession(on) |
| 92 | |
| 93 | const answer = ( |
| 94 | await $.command.run(Fixtures.record(Fixtures.surveyAnswer())) |
| 95 | ).text |
| 96 | |
| 97 | await session.clock.advance(Hooks.BATCH_WINDOW_MS) |
| 98 | |
| 99 | expect({ |
| 100 | answer, |
| 101 | posts: session.posts.length, |
| 102 | rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf), |
| 103 | }).toEqual({ |
| 104 | answer: 'queued', |
| 105 | posts: 1, |
| 106 | rows: ['tengu_plugin_survey_answered'], |
| 107 | }) |
| 108 | }, |
| 109 | ) |
| 110 | |
| 111 | test( |
| 112 | 'a step above cannot hand up its own telemetry in place of this one', |
| 113 | { plugins: [Fixtures.recording, Fixtures.replacing] }, |
| 114 | async ($, on) => { |
| 115 | mock.env(on, Fixtures.SENDING_ENV) |
| 116 | |
| 117 | const session = Fixtures.firstPartySession(on) |
| 118 | const own = (await $.command.run(Fixtures.typed('replace', {}))).text |
| 119 | |
| 120 | await $.command.run(Fixtures.record(Fixtures.surveyAnswer())) |
| 121 | await session.clock.advance(Hooks.BATCH_WINDOW_MS) |
| 122 | |
| 123 | expect({ |
| 124 | own, |
| 125 | rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf), |
| 126 | }).toEqual({ |
| 127 | own: `HooksError: replacing: $.telemetry.log: ${Hooks.REFUSED.deny}`, |
| 128 | rows: ['tengu_plugin_survey_answered'], |
| 129 | }) |
| 130 | }, |
| 131 | ) |
| 132 | |
| 133 | test( |
| 134 | 'a hook on every event cannot turn a row to the other destination', |
| 135 | { plugins: [Fixtures.recording, Fixtures.sweeping] }, |
| 136 | async ($, on) => { |
| 137 | mock.env(on, Fixtures.SENDING_ENV) |
| 138 | |
| 139 | const session = Fixtures.firstPartySession(on) |
| 140 | |
| 141 | await $.session.start(Fixtures.STARTED) |
| 142 | |
| 143 | const answer = ( |
| 144 | await $.command.run(Fixtures.record(Fixtures.surveyAnswer())) |
| 145 | ).text |
| 146 | |
| 147 | await session.clock.advance(Hooks.BATCH_WINDOW_MS) |
| 148 | |
| 149 | expect({ |
| 150 | answer, |
| 151 | posts: session.posts.length, |
| 152 | rows: Fixtures.rowsOf(session), |
| 153 | }).toEqual({ |
| 154 | answer: 'queued', |
| 155 | posts: 1, |
| 156 | rows: [Fixtures.EXPECTED_ROW], |
| 157 | }) |
| 158 | }, |
| 159 | ) |
| 160 | |
| 161 | test( |
| 162 | 'what a hook on every event adds beside a row never leaves in it', |
| 163 | { plugins: [Fixtures.recording, Fixtures.annotating] }, |
| 164 | async ($, on) => { |
| 165 | mock.env(on, Fixtures.SENDING_ENV) |
| 166 | |
| 167 | const session = Fixtures.firstPartySession(on) |
| 168 | |
| 169 | await $.session.start(Fixtures.STARTED) |
| 170 | |
| 171 | const answer = ( |
| 172 | await $.command.run(Fixtures.record(Fixtures.surveyAnswer())) |
| 173 | ).text |
| 174 | |
| 175 | await session.clock.advance(Hooks.BATCH_WINDOW_MS) |
| 176 | |
| 177 | expect({ |
| 178 | answer, |
| 179 | posts: session.posts.length, |
| 180 | rows: Fixtures.rowsOf(session), |
| 181 | }).toEqual({ |
| 182 | answer: 'queued', |
| 183 | posts: 1, |
| 184 | rows: [Fixtures.EXPECTED_ROW], |
| 185 | }) |
| 186 | }, |
| 187 | ) |
| 188 | }) |