mirror of
https://github.com/hanzoai/insights.git
synced 2026-10-30 16:15:31 +00:00
243 files rewritten and 12 renamed, by family rather than by a bare substring: stamphog->stamp, review_hog->review, supporthog->support, hogdesk->desk, personhog->person, hoggies->mascot, tophog->topfn, hogflow->flow, hogfunction->function, and hog->script for the rest. Also drops the last alias in the nodejs tree. @hanzo/[email protected] is ours and exports `class Insights` directly, so import { PostHog as Insights } from 'insights-node' becomes an import of the package that already has the name. The catalog entry aliasing insights-node onto posthog-node is no longer what nodejs depends on. Three exclusions, each one learned by breaking it first: migrations/ Django records an applied migration by (app, name). A first pass renamed 0224_tophog.py and three others; that makes them look unapplied and they run again. Reverted; the renamer now refuses any path under migrations/. whogho an integration vendor, sitting in generated_configs/ between Whop and WhenIWork. The same pass turned it into wscriptho.py. Held aside now, and untouched in this diff. case `s/hog/script/I` turned HogDebug.tsx into scriptDebug.tsx, so a component file stopped matching its export. Each rule carries its own casing: ScriptDebug.tsx, ScriptRepl.tsx, but scriptReplLogic.ts. Checked after: every changed .json still parses, and the diff introduces no word where `script` landed inside an unrelated English one — ORTHOGONAL contains "hog" and survives, as does every `subscription`. Co-authored-by: Hanzo Dev <[email protected]>
148 lines
6.0 KiB
TypeScript
148 lines
6.0 KiB
TypeScript
import { PlaywrightWorkspaceSetupResult, expect, test } from '../utils/workspace-test-base'
|
|
|
|
const TRIGGER_NODE_ID = 'trigger_node'
|
|
const EXIT_NODE_ID = 'exit_node'
|
|
const CAPTURE_NODE_ID = 'capture_node'
|
|
|
|
// `template-insights-capture` is shipped with `status: 'hidden'` (see
|
|
// nodejs/src/cdp/templates/_destinations/insights_capture/insights-capture.template.ts).
|
|
// The workflow editor loads every template via the authenticated project list and uses the
|
|
// resulting map to render each step's config. A previous change excluded hidden templates from
|
|
// that list, which made workflows containing this step render "Template not found!" and blocked
|
|
// editing or creating them. This test guards against that regression.
|
|
function buildWorkflowWithCaptureStep(): Record<string, any> {
|
|
return {
|
|
name: `Hidden template load ${Date.now()}`,
|
|
actions: [
|
|
{
|
|
id: TRIGGER_NODE_ID,
|
|
type: 'trigger',
|
|
name: 'Trigger',
|
|
description: 'Triggered by an event',
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
config: {
|
|
type: 'event',
|
|
filters: { events: [{ id: '$pageview', type: 'events' }] },
|
|
},
|
|
},
|
|
{
|
|
id: CAPTURE_NODE_ID,
|
|
type: 'function',
|
|
name: 'Capture a Insights event',
|
|
description: '',
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
config: {
|
|
template_id: 'template-insights-capture',
|
|
inputs: {},
|
|
},
|
|
},
|
|
{
|
|
id: EXIT_NODE_ID,
|
|
type: 'exit',
|
|
name: 'Exit',
|
|
description: 'Default exit',
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
config: { reason: 'Default exit' },
|
|
},
|
|
],
|
|
edges: [
|
|
{ from: TRIGGER_NODE_ID, to: CAPTURE_NODE_ID, type: 'continue' },
|
|
{ from: CAPTURE_NODE_ID, to: EXIT_NODE_ID, type: 'continue' },
|
|
],
|
|
conversion: { window_minutes: null, filters: [] },
|
|
exit_condition: 'exit_only_at_end',
|
|
version: 1,
|
|
status: 'draft',
|
|
}
|
|
}
|
|
|
|
test.describe('Workflows hidden built-in templates load', () => {
|
|
test.describe.configure({ mode: 'serial' })
|
|
test.setTimeout(90 * 1000)
|
|
|
|
let workspace: PlaywrightWorkspaceSetupResult | null = null
|
|
|
|
test.beforeAll(async ({ playwrightSetup }) => {
|
|
workspace = await playwrightSetup.createWorkspace({
|
|
skip_onboarding: true,
|
|
no_demo_data: true,
|
|
})
|
|
// Playwright CI doesn't run sync_insights_function_templates, so the templates table is
|
|
// empty. Seed the one this test references with status='hidden' — that's the regression
|
|
// class we want to catch (a server-side filter that strips hidden templates).
|
|
await playwrightSetup.seedInsightsFunctionTemplate({
|
|
template_id: 'template-insights-capture',
|
|
name: 'Capture a Insights event',
|
|
status: 'hidden',
|
|
template_type: 'destination',
|
|
inputs_schema: [
|
|
{
|
|
key: 'event',
|
|
type: 'string',
|
|
label: 'Event name',
|
|
required: true,
|
|
description: 'The name of the event to capture.',
|
|
},
|
|
],
|
|
})
|
|
})
|
|
|
|
test.beforeEach(async ({ page, playwrightSetup }) => {
|
|
await playwrightSetup.loginAndNavigateToTeam(page, workspace!)
|
|
})
|
|
|
|
test('opening a workflow whose step uses a hidden template renders its config (no "Template not found")', async ({
|
|
page,
|
|
}) => {
|
|
const teamId = workspace!.team_id
|
|
const workflowPayload = buildWorkflowWithCaptureStep()
|
|
const workflowId = await page.evaluate(
|
|
async ({ teamId, payload }) => {
|
|
const csrfToken =
|
|
document.cookie
|
|
.split(';')
|
|
.map((c) => c.trim())
|
|
.find((c) => c.startsWith('insights_csrftoken='))
|
|
?.split('=')
|
|
.slice(1)
|
|
.join('=') || ''
|
|
if (!csrfToken) {
|
|
throw new Error('CSRF cookie missing')
|
|
}
|
|
const response = await fetch(`/v1/environments/${teamId}/script_flows/`, {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': decodeURIComponent(csrfToken),
|
|
},
|
|
body: JSON.stringify(payload),
|
|
})
|
|
if (!response.ok) {
|
|
throw new Error(`script_flows POST failed: ${response.status} ${await response.text()}`)
|
|
}
|
|
const data = await response.json()
|
|
return data.id as string
|
|
},
|
|
{ teamId, payload: workflowPayload }
|
|
)
|
|
|
|
await test.step('open the workflow editor and select the capture step', async () => {
|
|
await page.goto(`/workflows/${workflowId}/workflow`)
|
|
await page.waitForSelector('[data-attr="workflow-editor"]', { timeout: 30000 })
|
|
await page.locator(`[data-testid="rf__node-${CAPTURE_NODE_ID}"]`).click()
|
|
})
|
|
|
|
await test.step('the template config renders instead of the not-found fallback', async () => {
|
|
// `template-insights-capture` declares an "Event name" input in its inputs_schema.
|
|
// If the project list omitted hidden templates, the panel would render
|
|
// <div>Template not found!</div> and this label would never appear.
|
|
await expect(page.getByText('Event name', { exact: true })).toBeVisible({ timeout: 15000 })
|
|
await expect(page.getByText('Template not found!')).toHaveCount(0)
|
|
})
|
|
})
|
|
})
|