chore: replace tsx with native Node TypeScript execution (#42742)

This commit is contained in:
Stephen Zhou
2026-09-22 11:23:20 +00:00
committed by GitHub
parent 5b6e850b25
commit 1fc040183c
178 changed files with 538 additions and 564 deletions

View File

@@ -80,7 +80,7 @@ jobs:
if [[ "$WCAG_PAGE" == "all" ]]; then
vp run e2e:accessibility:${{ inputs.level }}
else
pnpm exec tsx ./scripts/run-cucumber.ts --full -- --tags "@axe and @wcag-${{ inputs.level }} and @wcag-page-$WCAG_PAGE"
pnpm exec node ./scripts/run-cucumber.ts --full -- --tags "@axe and @wcag-${{ inputs.level }} and @wcag-page-$WCAG_PAGE"
fi
- name: Upload accessibility Cucumber report

View File

@@ -51,7 +51,7 @@ jobs:
- name: Run smoke against live dify
working-directory: ./cli
run: pnpm exec tsx scripts/run-smoke.ts --base-url http://localhost:5001
run: pnpm exec node scripts/run-smoke.ts --base-url http://localhost:5001
- name: Dump dify logs on failure
if: failure()

View File

@@ -36,7 +36,6 @@ jobs:
- 'e2e/package.json'
- 'e2e/test-env.ts'
- 'e2e/tsconfig.json'
- 'e2e/tsx-register.js'
- 'package.json'
- 'pnpm-lock.yaml'
- '.github/workflows/post-merge.yml'

View File

@@ -9,7 +9,7 @@ Run commands from the repository root. Install dependencies and browsers once wi
- Existing initialized instance: `pnpm -C e2e e2e`
- Standalone automated WCAG Level A scan: `pnpm -C e2e e2e:accessibility:a`
- Standalone automated WCAG Level AA scan: `pnpm -C e2e e2e:accessibility:aa`
- One-page automated WCAG scan: `pnpm -C e2e exec tsx ./scripts/run-cucumber.ts --full -- --tags "@axe and @wcag-a and @wcag-page-studio"` (replace the level and page tag as needed)
- One-page automated WCAG scan: `pnpm -C e2e exec node ./scripts/run-cucumber.ts --full -- --tags "@axe and @wcag-a and @wcag-page-studio"` (replace the level and page tag as needed)
- Reset, initialize, and run deterministic scenarios: `pnpm -C e2e e2e:full`
- Prepare and run scenarios backed by shared fixtures: `E2E_START_AGENT_BACKEND=1 pnpm -C e2e e2e:prepared`
- Tagged subset: `pnpm -C e2e e2e -- --tags @smoke`

View File

@@ -1,5 +1,5 @@
import type { IConfiguration } from '@cucumber/cucumber'
import './scripts/env-register'
import './scripts/env-register.ts'
const hasCliTags = process.argv.some((arg) => arg === '--tags' || arg.startsWith('--tags='))
const defaultNonExternalTags =
@@ -15,7 +15,7 @@ const config = {
'html:./cucumber-report/report.html',
'message:./cucumber-report/report.ndjson',
],
import: ['./tsx-register.js', 'features/**/*.ts'],
import: ['features/**/*.ts'],
paths: ['features/**/*.feature'],
tags,
timeout: 60_000,

View File

@@ -1,6 +1,6 @@
import type { AgentAppDetailWithSite } from '@dify/contracts/api/console/agent/types.gen'
import type { ChatRequestPayloadWithUser } from '@dify/contracts/api/service/types.gen'
import { consumeServiceApiSse, SERVICE_API_STREAM_TIMEOUT_MS } from './service-api-sse'
import { consumeServiceApiSse, SERVICE_API_STREAM_TIMEOUT_MS } from './service-api-sse.ts'
export type AgentServiceApiChatResult = {
body: unknown

View File

@@ -2,7 +2,7 @@ import type {
AgentBuildDraftResponse,
AgentSoulConfig,
} from '@dify/contracts/api/console/agent/types.gen'
import type { ConsoleClient } from '../../../support/api/console-client'
import type { ConsoleClient } from '../../../support/api/console-client.ts'
import { ORPCError } from '@orpc/client'
export async function saveAgentBuildDraft(

View File

@@ -6,13 +6,13 @@ import type {
AgentReferencingWorkflowsResponse,
AgentSoulConfig,
} from '@dify/contracts/api/console/agent/types.gen'
import type { ConsoleClient } from '../../../support/api/console-client'
import { assertE2EResourceName, createE2EResourceName } from '../../../support/naming'
import type { ConsoleClient } from '../../../support/api/console-client.ts'
import { assertE2EResourceName, createE2EResourceName } from '../../../support/naming.ts'
import {
createPublishableAgentSoulConfig,
defaultAgentSoulConfig,
normalAgentSoulConfig,
} from './agent-soul'
} from './agent-soul.ts'
export type CreateTestAgentOptions = {
description?: string

View File

@@ -4,7 +4,7 @@ import type {
AgentConfigSkillRefConfig,
AgentConfigSkillUploadResponse,
} from '@dify/contracts/api/console/agent/types.gen'
import type { ConsoleClient } from '../../../support/api/console-client'
import type { ConsoleClient } from '../../../support/api/console-client.ts'
import { Buffer } from 'node:buffer'
import { readFile } from 'node:fs/promises'
import path from 'node:path'

View File

@@ -1,8 +1,8 @@
import type { ConsoleClient } from '../../../../support/api/console-client'
import type { DifyWorld } from '../../../support/world'
import type { PreseededResource } from './common'
import { requirePreseededAgent, requirePreseededWorkflow } from './agents'
import { failFixturePrerequisite } from './common'
import type { ConsoleClient } from '../../../../support/api/console-client.ts'
import type { DifyWorld } from '../../../support/world.ts'
import type { PreseededResource } from './common.ts'
import { requirePreseededAgent, requirePreseededWorkflow } from './agents.ts'
import { failFixturePrerequisite } from './common.ts'
export async function requirePreseededAgentWorkflowReference(
world: DifyWorld,

View File

@@ -1,5 +1,5 @@
import type { DifyWorld } from '../../../support/world'
import { failFixturePrerequisite } from './common'
import type { DifyWorld } from '../../../support/world.ts'
import { failFixturePrerequisite } from './common.ts'
const isTruthyEnv = (value: string | undefined) => value === '1' || value === 'true'

View File

@@ -1,12 +1,12 @@
import type { ConsoleClient } from '../../../../support/api/console-client'
import type { DifyWorld } from '../../../support/world'
import type { PreseededResource } from './common'
import type { ConsoleClient } from '../../../../support/api/console-client.ts'
import type { DifyWorld } from '../../../support/world.ts'
import type { PreseededResource } from './common.ts'
import {
agentBuilderExpectedTokens,
agentBuilderFixedInputs,
agentBuilderPreseededResources,
} from '../agent-builder-resources'
import { agentBuilderTestMaterials } from '../test-materials'
} from '../agent-builder-resources.ts'
import { agentBuilderTestMaterials } from '../test-materials.ts'
import {
asArray,
asRecord,
@@ -14,9 +14,9 @@ import {
failFixturePrerequisite,
findResourceByName,
hasNamedOrKeyedEntry,
} from './common'
import { requireReadyPreseededDataset } from './datasets'
import { requireAgentBuilderStableChatModel } from './models'
} from './common.ts'
import { requireReadyPreseededDataset } from './datasets.ts'
import { requireAgentBuilderStableChatModel } from './models.ts'
import {
findToolEntry,
hasToolEntry,
@@ -24,7 +24,7 @@ import {
requirePreseededTool,
splitToolDisplayName,
splitToolResourceId,
} from './tools'
} from './tools.ts'
const hasKnowledgeDataset = (soul: Record<string, unknown>, dataset: PreseededResource) => {
const knowledge = asRecord(soul.knowledge)

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../../support/world'
import type { DifyWorld } from '../../../support/world.ts'
export type PreseededResource = NonNullable<
DifyWorld['agentBuilder']['fixtures']['preseededResources'][string]

View File

@@ -2,15 +2,15 @@ import type {
DatasetListItemResponse,
DocumentWithSegmentsListResponse,
} from '@dify/contracts/api/console/datasets/types.gen'
import type { ConsoleClient } from '../../../../support/api/console-client'
import type { DifyWorld } from '../../../support/world'
import type { PreseededResource } from './common'
import type { ConsoleClient } from '../../../../support/api/console-client.ts'
import type { DifyWorld } from '../../../support/world.ts'
import type { PreseededResource } from './common.ts'
import {
agentBuilderExpectedTokens,
agentBuilderFixedInputs,
agentBuilderPreseededResources,
} from '../agent-builder-resources'
import { failFixturePrerequisite, findResourceByName } from './common'
} from '../agent-builder-resources.ts'
import { failFixturePrerequisite, findResourceByName } from './common.ts'
type DocumentIndexingStatus =
| 'cleaning'

View File

@@ -1,7 +1,7 @@
import type { ConsoleClient } from '../../../../support/api/console-client'
import type { DifyWorld } from '../../../support/world'
import { agentBuilderPreseededResources } from '../agent-builder-resources'
import { failFixturePrerequisite } from './common'
import type { ConsoleClient } from '../../../../support/api/console-client.ts'
import type { DifyWorld } from '../../../support/world.ts'
import { agentBuilderPreseededResources } from '../agent-builder-resources.ts'
import { failFixturePrerequisite } from './common.ts'
const stableChatModelProviderEnv = 'E2E_STABLE_MODEL_PROVIDER'
const stableChatModelNameEnv = 'E2E_STABLE_MODEL_NAME'

View File

@@ -1,7 +1,7 @@
import type { ConsoleClient } from '../../../../support/api/console-client'
import type { DifyWorld } from '../../../support/world'
import type { PreseededResource } from './common'
import { asRecord, asString, failFixturePrerequisite, matchesNameOrLabel } from './common'
import type { ConsoleClient } from '../../../../support/api/console-client.ts'
import type { DifyWorld } from '../../../support/world.ts'
import type { PreseededResource } from './common.ts'
import { asRecord, asString, failFixturePrerequisite, matchesNameOrLabel } from './common.ts'
export const splitToolDisplayName = (resourceName: string) => {
const [providerName, toolName] = resourceName.split('/').map((item) => item.trim())

View File

@@ -5,28 +5,28 @@ import type {
} from '@dify/contracts/api/console/agent/types.gen'
import type { KnowledgeConfig } from '@dify/contracts/api/console/datasets/types.gen'
import type { ModelType } from '@dify/contracts/api/console/workspaces/types.gen'
import type { SeedContext, SeedResource, SeedTask } from '../../../support/seed'
import type { SeedContext, SeedResource, SeedTask } from '../../../support/seed.ts'
import { readFile } from 'node:fs/promises'
import { createTestApp } from '../../../support/api/apps'
import { bootstrapMarketplacePlugins } from '../../../support/marketplace-plugins'
import { sleep } from '../../../support/process'
import { blocked, created, skipped, updated, verified } from '../../../support/seed'
import { createTestAgent, saveAgentComposerDraft } from './agent'
import { createTestApp } from '../../../support/api/apps.ts'
import { bootstrapMarketplacePlugins } from '../../../support/marketplace-plugins.ts'
import { sleep } from '../../../support/process.ts'
import { blocked, created, skipped, updated, verified } from '../../../support/seed.ts'
import {
agentBuilderExpectedTokens,
agentBuilderFixedInputs,
agentBuilderPreseededResources,
} from './agent-builder-resources'
} from './agent-builder-resources.ts'
import {
createAgentSoulConfigWithKnowledgeDataset,
createAgentSoulConfigWithModel,
normalAgentSoulConfig,
} from './agent-soul'
import { uploadAgentConfigFileToDraft, uploadAgentConfigSkillToDraft } from './config-assets'
import { isRecord, matchesNameOrLabel } from './fixtures/common'
import { splitToolDisplayName } from './fixtures/tools'
import { agentBuilderTestMaterials, getAgentBuilderTestMaterialPath } from './test-materials'
import { syncAgentV2WorkflowDraft } from './workflow'
} from './agent-soul.ts'
import { createTestAgent, saveAgentComposerDraft } from './agent.ts'
import { uploadAgentConfigFileToDraft, uploadAgentConfigSkillToDraft } from './config-assets.ts'
import { isRecord, matchesNameOrLabel } from './fixtures/common.ts'
import { splitToolDisplayName } from './fixtures/tools.ts'
import { agentBuilderTestMaterials, getAgentBuilderTestMaterialPath } from './test-materials.ts'
import { syncAgentV2WorkflowDraft } from './workflow.ts'
type StableModel = {
name: string

View File

@@ -1,4 +1,7 @@
import { getGeneratedTextMaterialPath, getTestMaterialPath } from '../../../support/test-materials'
import {
getGeneratedTextMaterialPath,
getTestMaterialPath,
} from '../../../support/test-materials.ts'
export const agentBuilderTestMaterials = {
smallFile: 'agent-small-file.txt',

View File

@@ -1,5 +1,5 @@
import type { DifyWorld } from '../../support/world'
import { splitToolDisplayName, splitToolResourceId } from './fixtures/tools'
import type { DifyWorld } from '../../support/world.ts'
import { splitToolDisplayName, splitToolResourceId } from './fixtures/tools.ts'
export const getPreseededToolContract = (world: DifyWorld, resourceName: string) => {
const resource = world.agentBuilder.fixtures.preseededResources[resourceName]

View File

@@ -1,5 +1,5 @@
import type { SyncDraftWorkflowPayload } from '@dify/contracts/api/console/apps/types.gen'
import type { ConsoleClient } from '../../../support/api/console-client'
import type { ConsoleClient } from '../../../support/api/console-client.ts'
import * as z from 'zod'
const agentV2WorkflowNodeId = 'agent-v2'

View File

@@ -1,5 +1,5 @@
import type { DifyWorld } from '../../support/world'
import AxeBuilder from '@axe-core/playwright'
import type { DifyWorld } from '../../support/world.ts'
import { AxeBuilder } from '@axe-core/playwright'
import { Then } from '@cucumber/cucumber'
import { expect } from '@playwright/test'

View File

@@ -1,8 +1,8 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { adminCredentials } from '../../../fixtures/auth'
import { e2eBrowser } from '../../../test-env'
import { adminCredentials } from '../../../fixtures/auth.ts'
import { e2eBrowser } from '../../../test-env.ts'
const getAccountMenuTrigger = (world: DifyWorld) =>
world.getPage().getByRole('button', { name: 'Account' })

View File

@@ -1,11 +1,11 @@
import type { Page } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { waitForAgentsConsole } from '../../../support/agents'
import { waitForAppsConsole } from '../../../support/apps'
import { waitForConsoleHome } from '../../../support/home'
import { waitForModelProviderIntegrations } from '../../../support/integrations'
import { waitForKnowledgeConsole } from '../../../support/knowledge'
import { waitForAgentsConsole } from '../../../support/agents.ts'
import { waitForAppsConsole } from '../../../support/apps.ts'
import { waitForConsoleHome } from '../../../support/home.ts'
import { waitForModelProviderIntegrations } from '../../../support/integrations.ts'
import { waitForKnowledgeConsole } from '../../../support/knowledge.ts'
type AccessibilityPageConfig = {
path: string

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
export const getCurrentAgentId = (world: DifyWorld) => {
const agentId = world.createdAgentIds.at(-1)

View File

@@ -1,13 +1,13 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { sendAgentServiceApiChatMessage } from '../../agent-v2/support/access-point'
import { sendAgentServiceApiChatMessage } from '../../agent-v2/support/access-point.ts'
import {
agentBuilderExpectedTokens,
agentBuilderFixedInputs,
} from '../../agent-v2/support/agent-builder-resources'
import { SERVICE_API_RUNTIME_STEP_TIMEOUT_MS } from '../../agent-v2/support/service-api-sse'
import { getCurrentAgentId, getServiceApiCard } from './access-point-helpers'
} from '../../agent-v2/support/agent-builder-resources.ts'
import { SERVICE_API_RUNTIME_STEP_TIMEOUT_MS } from '../../agent-v2/support/service-api-sse.ts'
import { getCurrentAgentId, getServiceApiCard } from './access-point-helpers.ts'
const API_KEY_DIALOG_NAME = /^API Key$/i

View File

@@ -1,10 +1,10 @@
import type { Page } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { getAgentWebAppURL } from '../../agent-v2/support/access-point'
import { agentBuilderExpectedTokens } from '../../agent-v2/support/agent-builder-resources'
import { getCurrentAgentId, getDialog, getWebAppCard } from './access-point-helpers'
import { getAgentWebAppURL } from '../../agent-v2/support/access-point.ts'
import { agentBuilderExpectedTokens } from '../../agent-v2/support/agent-builder-resources.ts'
import { getCurrentAgentId, getDialog, getWebAppCard } from './access-point-helpers.ts'
const WEB_APP_RUNTIME_RESPONSE_STEP_TIMEOUT_MS = 180_000

View File

@@ -1,9 +1,9 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { getAgentReferencingWorkflows } from '../../agent-v2/support/agent'
import { agentBuilderPreseededResources } from '../../agent-v2/support/agent-builder-resources'
import { getAccessRegion, getPreseededResource } from './access-point-helpers'
import { agentBuilderPreseededResources } from '../../agent-v2/support/agent-builder-resources.ts'
import { getAgentReferencingWorkflows } from '../../agent-v2/support/agent.ts'
import { getAccessRegion, getPreseededResource } from './access-point-helpers.ts'
Then(
'I should see the Agent v2 Workflow access reference for {string}',

View File

@@ -1,15 +1,15 @@
import type { DifyWorld } from '../../support/world'
import type { AccessSurfaceName } from './access-point-helpers'
import type { DifyWorld } from '../../support/world.ts'
import type { AccessSurfaceName } from './access-point-helpers.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { publishAgentWithPublishableDraft } from '../../agent-v2/support/agent'
import { publishAgentWithPublishableDraft } from '../../agent-v2/support/agent.ts'
import {
getAccessSurfaceCard,
getCurrentAgentId,
getPreseededResource,
getServiceApiCard,
getWebAppCard,
} from './access-point-helpers'
} from './access-point-helpers.ts'
const toggleAgentAccess = async (
world: DifyWorld,

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'

View File

@@ -1,22 +1,22 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { zPostAgentByAgentIdCopyResponse } from '@dify/contracts/api/console/agent/zod.gen'
import { expect } from '@playwright/test'
import { createE2EResourceName } from '../../../support/naming'
import { createE2EResourceName } from '../../../support/naming.ts'
import {
agentBuilderExpectedTokens,
agentBuilderFixedInputs,
agentBuilderPreseededResources,
} from '../../agent-v2/support/agent-builder-resources'
import { normalAgentPrompt } from '../../agent-v2/support/agent-soul'
import { asArray, asRecord, asString } from '../../agent-v2/support/fixtures/common'
import { agentBuilderTestMaterials } from '../../agent-v2/support/test-materials'
} from '../../agent-v2/support/agent-builder-resources.ts'
import { normalAgentPrompt } from '../../agent-v2/support/agent-soul.ts'
import { asArray, asRecord, asString } from '../../agent-v2/support/fixtures/common.ts'
import { agentBuilderTestMaterials } from '../../agent-v2/support/test-materials.ts'
import {
expectProviderToolActionVisible,
getCurrentAgentId,
getPreseededAgent,
openAgentKnowledgeRetrievalDialog,
} from './configure-helpers'
} from './configure-helpers.ts'
const getComposerInheritanceSnapshot = async (world: DifyWorld, agentId: string) => {
const draft = await world

View File

@@ -1,8 +1,8 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { zPostAgentResponse } from '@dify/contracts/api/console/agent/zod.gen'
import { expect } from '@playwright/test'
import { createE2EResourceName } from '../../../support/naming'
import { createE2EResourceName } from '../../../support/naming.ts'
When('I create an Agent v2 test agent from the Agent Roster', async function (this: DifyWorld) {
const page = this.getPage()

View File

@@ -1,36 +1,36 @@
import type { AgentBuildDraftResponse } from '@dify/contracts/api/console/agent/types.gen'
import type { Page, Response } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { readFile } from 'node:fs/promises'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { saveAgentComposerDraft } from '../../agent-v2/support/agent'
import {
agentBuildDraftExists,
saveAgentBuildDraft,
} from '../../agent-v2/support/agent-build-draft'
} from '../../agent-v2/support/agent-build-draft.ts'
import {
agentBuilderFixedInputs,
agentBuilderPreseededResources,
} from '../../agent-v2/support/agent-builder-resources'
} from '../../agent-v2/support/agent-builder-resources.ts'
import {
createAgentSoulConfigWithModel,
normalAgentPrompt,
normalAgentSoulConfig,
updatedAgentPrompt,
updatedAgentSoulConfig,
} from '../../agent-v2/support/agent-soul'
import { uploadAgentConfigFileToDraft } from '../../agent-v2/support/config-assets'
} from '../../agent-v2/support/agent-soul.ts'
import { saveAgentComposerDraft } from '../../agent-v2/support/agent.ts'
import { uploadAgentConfigFileToDraft } from '../../agent-v2/support/config-assets.ts'
import {
agentBuilderTestMaterials,
getAgentBuilderTestMaterialPath,
} from '../../agent-v2/support/test-materials'
} from '../../agent-v2/support/test-materials.ts'
import {
expectAgentModelRequiredFeedback,
getAgentEnvVariableValue,
getCurrentAgentId,
uploadSummaryConfigSkillForBuildDraft,
} from './configure-helpers'
} from './configure-helpers.ts'
const BUILD_DRAFT_RUNTIME_STEP_TIMEOUT_MS = 180_000
const BUILD_DRAFT_NOTE_SYNC_TIMEOUT_MS = 30_000

View File

@@ -1,14 +1,14 @@
import type { Locator } from '@playwright/test'
import type { AgentComposerEnvVariable } from '../../agent-v2/support/agent-soul'
import type { DifyWorld } from '../../support/world'
import type { AgentComposerEnvVariable } from '../../agent-v2/support/agent-soul.ts'
import type { DifyWorld } from '../../support/world.ts'
import { zPostAgentByAgentIdConfigFilesResponse } from '@dify/contracts/api/console/agent/zod.gen'
import { expect } from '@playwright/test'
import { normalAgentPrompt } from '../../agent-v2/support/agent-soul'
import { uploadAgentConfigSkillToDraft } from '../../agent-v2/support/config-assets'
import { normalAgentPrompt } from '../../agent-v2/support/agent-soul.ts'
import { uploadAgentConfigSkillToDraft } from '../../agent-v2/support/config-assets.ts'
import {
agentBuilderTestMaterials,
getAgentBuilderTestMaterialPath,
} from '../../agent-v2/support/test-materials'
} from '../../agent-v2/support/test-materials.ts'
export const getCurrentAgentId = (world: DifyWorld) => {
const agentId = world.createdAgentIds.at(-1)

View File

@@ -1,14 +1,8 @@
import type { Page } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { waitForAgentConfigureAutosaved } from '../../../support/agent-configure'
import {
createConfiguredTestAgent,
createTestAgent,
getAgentConfigurePath,
saveAgentComposerDraft,
} from '../../agent-v2/support/agent'
import { waitForAgentConfigureAutosaved } from '../../../support/agent-configure.ts'
import {
concurrentFirstAgentPrompt,
concurrentSecondAgentPrompt,
@@ -17,12 +11,18 @@ import {
normalAgentPrompt,
normalAgentSoulConfig,
updatedAgentPrompt,
} from '../../agent-v2/support/agent-soul'
} from '../../agent-v2/support/agent-soul.ts'
import {
createConfiguredTestAgent,
createTestAgent,
getAgentConfigurePath,
saveAgentComposerDraft,
} from '../../agent-v2/support/agent.ts'
import {
expectNormalAgentPromptDraft,
getCurrentAgentId,
getPreseededAgent,
} from './configure-helpers'
} from './configure-helpers.ts'
const concurrentAgentPrompts = [concurrentFirstAgentPrompt, concurrentSecondAgentPrompt]

View File

@@ -1,8 +1,8 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { agentBuilderFixedInputs } from '../../agent-v2/support/agent-builder-resources'
import { getAgentBuilderTestMaterialPath } from '../../agent-v2/support/test-materials'
import { agentBuilderFixedInputs } from '../../agent-v2/support/agent-builder-resources.ts'
import { getAgentBuilderTestMaterialPath } from '../../agent-v2/support/test-materials.ts'
import {
expectAgentEnvVariableAbsent,
expectAgentEnvVariableHidden,
@@ -14,7 +14,7 @@ import {
getCurrentAgentId,
getEnvVariableKey,
openAgentAdvancedSettings,
} from './configure-helpers'
} from './configure-helpers.ts'
When(
'I add the plain Agent v2 environment variable from Advanced Settings',

View File

@@ -1,13 +1,13 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { agentBuilderTestMaterials } from '../../agent-v2/support/test-materials'
import { agentBuilderTestMaterials } from '../../agent-v2/support/test-materials.ts'
import {
expectAgentConfigFileHidden,
expectAgentConfigFileSaved,
expectAgentConfigFileVisible,
uploadAgentConfigFile,
} from './configure-helpers'
} from './configure-helpers.ts'
When('I upload the small Agent v2 file from the Files section', async function (this: DifyWorld) {
await uploadAgentConfigFile(this, 'smallFile')

View File

@@ -1,21 +1,21 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given } from '@cucumber/cucumber'
import { requirePreseededAgentWorkflowReference } from '../../agent-v2/support/fixtures/access'
import { requireAgentBackendRuntime } from '../../agent-v2/support/fixtures/agent-backend'
import { requirePreseededAgentWorkflowReference } from '../../agent-v2/support/fixtures/access.ts'
import { requireAgentBackendRuntime } from '../../agent-v2/support/fixtures/agent-backend.ts'
import {
requirePreseededAgent,
requirePreseededDualRetrievalAgentConfiguration,
requirePreseededFullConfigAgentCoreConfiguration,
requirePreseededToolStatesAgentConfiguration,
requirePreseededWorkflow,
} from '../../agent-v2/support/fixtures/agents'
import { requireReadyPreseededDataset } from '../../agent-v2/support/fixtures/datasets'
} from '../../agent-v2/support/fixtures/agents.ts'
import { requireReadyPreseededDataset } from '../../agent-v2/support/fixtures/datasets.ts'
import {
requireAgentBuilderAgentDecisionChatModel,
requireAgentBuilderSpeechToTextModel,
requireAgentBuilderStableChatModel,
} from '../../agent-v2/support/fixtures/models'
import { requirePreseededTool } from '../../agent-v2/support/fixtures/tools'
} from '../../agent-v2/support/fixtures/models.ts'
import { requirePreseededTool } from '../../agent-v2/support/fixtures/tools.ts'
Given('the Agent Builder stable chat model is available', async function (this: DifyWorld) {
const stableModel = await requireAgentBuilderStableChatModel(this, this.getConsoleClient())

View File

@@ -1,18 +1,18 @@
import type { Locator } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent'
import {
agentBuilderFixedInputs,
agentBuilderPreseededResources,
} from '../../agent-v2/support/agent-builder-resources'
} from '../../agent-v2/support/agent-builder-resources.ts'
import {
createAgentSoulConfigWithKnowledgeDataset,
normalAgentSoulConfig,
} from '../../agent-v2/support/agent-soul'
import { asArray, asRecord } from '../../agent-v2/support/fixtures/common'
import { getCurrentAgentId } from './configure-helpers'
} from '../../agent-v2/support/agent-soul.ts'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent.ts'
import { asArray, asRecord } from '../../agent-v2/support/fixtures/common.ts'
import { getCurrentAgentId } from './configure-helpers.ts'
const getPreseededKnowledgeBase = (world: DifyWorld) => {
const resource =

View File

@@ -1,11 +1,11 @@
import type { DataTable } from '@cucumber/cucumber'
import type { DeclaredOutputConfig } from '@dify/contracts/api/console/apps/types.gen'
import type { AgentV2WorkflowOutputVariable, DifyWorld } from '../../support/world'
import type { AgentV2WorkflowOutputVariable, DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { zDeclaredOutputConfig } from '@dify/contracts/api/console/apps/zod.gen'
import { expect } from '@playwright/test'
import * as z from 'zod'
import { getAgentV2WorkflowNodeData } from '../../agent-v2/support/workflow'
import { getAgentV2WorkflowNodeData } from '../../agent-v2/support/workflow.ts'
const taskOutputName = 'e2e_report'
const renamedTaskOutputName = 'e2e_final_report'

View File

@@ -1,8 +1,8 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { waitForAgentConfigureAutosaved } from '../../../support/agent-configure'
import { expectAgentModelRequiredFeedback, getCurrentAgentId } from './configure-helpers'
import { waitForAgentConfigureAutosaved } from '../../../support/agent-configure.ts'
import { expectAgentModelRequiredFeedback, getCurrentAgentId } from './configure-helpers.ts'
When('I publish the Agent v2 draft', async function (this: DifyWorld) {
const page = this.getPage()

View File

@@ -1,13 +1,13 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { voiceInputTestMaterial } from '../../../support/test-materials'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent'
import { voiceInputTestMaterial } from '../../../support/test-materials.ts'
import {
createAgentSoulConfigWithSpeechToText,
normalAgentSoulConfig,
} from '../../agent-v2/support/agent-soul'
import { getCurrentAgentId } from './configure-helpers'
} from '../../agent-v2/support/agent-soul.ts'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent.ts'
import { getCurrentAgentId } from './configure-helpers.ts'
const getAgentInput = (world: DifyWorld) =>
world.getPage().getByPlaceholder('Describe what your agent should do')

View File

@@ -1,23 +1,23 @@
import type { AgentSoulDifyToolConfig } from '@dify/contracts/api/console/agent/types.gen'
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { sendAgentServiceApiChatMessage } from '../../agent-v2/support/access-point'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent'
import { sendAgentServiceApiChatMessage } from '../../agent-v2/support/access-point.ts'
import {
agentBuilderExpectedTokens,
agentBuilderPreseededResources,
} from '../../agent-v2/support/agent-builder-resources'
} from '../../agent-v2/support/agent-builder-resources.ts'
import {
createAgentSoulConfigWithDifyTool,
createAgentSoulConfigWithModel,
normalAgentSoulConfig,
} from '../../agent-v2/support/agent-soul'
import { asArray, asRecord, asString } from '../../agent-v2/support/fixtures/common'
import { hasToolEntry } from '../../agent-v2/support/fixtures/tools'
import { SERVICE_API_RUNTIME_STEP_TIMEOUT_MS } from '../../agent-v2/support/service-api-sse'
import { getPreseededToolContract } from '../../agent-v2/support/tools'
import { expectProviderToolActionVisible, getCurrentAgentId } from './configure-helpers'
} from '../../agent-v2/support/agent-soul.ts'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent.ts'
import { asArray, asRecord, asString } from '../../agent-v2/support/fixtures/common.ts'
import { hasToolEntry } from '../../agent-v2/support/fixtures/tools.ts'
import { SERVICE_API_RUNTIME_STEP_TIMEOUT_MS } from '../../agent-v2/support/service-api-sse.ts'
import { getPreseededToolContract } from '../../agent-v2/support/tools.ts'
import { expectProviderToolActionVisible, getCurrentAgentId } from './configure-helpers.ts'
const getToolsSection = (world: DifyWorld) => world.getPage().getByRole('region', { name: 'Tools' })

View File

@@ -1,15 +1,15 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { createTestApp } from '../../../support/api/apps'
import { createE2EResourceName } from '../../../support/naming'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent'
import { createTestApp } from '../../../support/api/apps.ts'
import { createE2EResourceName } from '../../../support/naming.ts'
import {
createAgentSoulConfigWithModel,
normalAgentPrompt,
normalAgentSoulConfig,
} from '../../agent-v2/support/agent-soul'
import { syncAgentV2WorkflowDraft } from '../../agent-v2/support/workflow'
} from '../../agent-v2/support/agent-soul.ts'
import { createConfiguredTestAgent } from '../../agent-v2/support/agent.ts'
import { syncAgentV2WorkflowDraft } from '../../agent-v2/support/workflow.ts'
Given(
'a workflow app with an Agent v2 node has been created via API',

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { When } from '@cucumber/cucumber'
When('I navigate to the app access point page', async function (this: DifyWorld) {

View File

@@ -1,9 +1,9 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { zPostAppsResponse } from '@dify/contracts/api/console/apps/zod.gen'
import { expect } from '@playwright/test'
import { openBlankAppCreation } from '../../../support/apps'
import { createE2EResourceName } from '../../../support/naming'
import { openBlankAppCreation } from '../../../support/apps.ts'
import { createE2EResourceName } from '../../../support/naming.ts'
const appModeByType: Record<string, string> = {
Agent: 'agent-chat',

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'

View File

@@ -1,10 +1,10 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, When } from '@cucumber/cucumber'
import { zPostAppsByAppIdCopyResponse } from '@dify/contracts/api/console/apps/zod.gen'
import { expect } from '@playwright/test'
import { createTestApp } from '../../../support/api/apps'
import { waitForAppsConsole } from '../../../support/apps'
import { createE2EResourceName } from '../../../support/naming'
import { createTestApp } from '../../../support/api/apps.ts'
import { waitForAppsConsole } from '../../../support/apps.ts'
import { createE2EResourceName } from '../../../support/naming.ts'
Given('there is an existing E2E app available for testing', async function (this: DifyWorld) {
const name = createE2EResourceName('App', 'Test')

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Buffer } from 'node:buffer'
import { readFile } from 'node:fs/promises'
import { Then } from '@cucumber/cucumber'

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'

View File

@@ -1,10 +1,10 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { createTestApp } from '../../../support/api/apps'
import { getAppSiteURL } from '../../../support/api/web-apps'
import { syncRunnableWorkflowDraft } from '../../../support/api/workflows'
import { createE2EResourceName } from '../../../support/naming'
import { createTestApp } from '../../../support/api/apps.ts'
import { getAppSiteURL } from '../../../support/api/web-apps.ts'
import { syncRunnableWorkflowDraft } from '../../../support/api/workflows.ts'
import { createE2EResourceName } from '../../../support/naming.ts'
Given('a workflow app has been published and shared via API', async function (this: DifyWorld) {
const client = this.getConsoleClient()

View File

@@ -1,8 +1,8 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { createTestApp } from '../../../support/api/apps'
import { createE2EResourceName } from '../../../support/naming'
import { createTestApp } from '../../../support/api/apps.ts'
import { createE2EResourceName } from '../../../support/naming.ts'
Given(
'there is an existing E2E completion app available for testing',

View File

@@ -1,11 +1,11 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { createTestApp } from '../../../support/api/apps'
import { getAppSiteURL } from '../../../support/api/web-apps'
import { syncRunnableWorkflowDraft } from '../../../support/api/workflows'
import { createE2EResourceName } from '../../../support/naming'
import { baseURL, defaultLocale } from '../../../test-env'
import { createTestApp } from '../../../support/api/apps.ts'
import { getAppSiteURL } from '../../../support/api/web-apps.ts'
import { syncRunnableWorkflowDraft } from '../../../support/api/workflows.ts'
import { createE2EResourceName } from '../../../support/naming.ts'
import { baseURL, defaultLocale } from '../../../test-env.ts'
Given('a new runnable workflow app has been published', async function (this: DifyWorld) {
const client = this.getConsoleClient()

View File

@@ -1,7 +1,7 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { syncRunnableWorkflowDraft } from '../../../support/api/workflows'
import { syncRunnableWorkflowDraft } from '../../../support/api/workflows.ts'
Given('a minimal runnable workflow draft has been synced', async function (this: DifyWorld) {
const appId = this.createdAppIds.at(-1)

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'

View File

@@ -1,6 +1,6 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { When } from '@cucumber/cucumber'
import { adminCredentials } from '../../../fixtures/auth'
import { adminCredentials } from '../../../fixtures/auth.ts'
When('I open the sign-in page', async function (this: DifyWorld) {
await this.getPage().goto('/signin')

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'

View File

@@ -1,11 +1,11 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given, When } from '@cucumber/cucumber'
import { zCreateAppPayload } from '@dify/contracts/api/console/apps/zod.gen'
import { expect } from '@playwright/test'
import { createTestApp } from '../../../support/api/apps'
import { syncMinimalWorkflowDraft } from '../../../support/api/workflows'
import { waitForAppsConsole } from '../../../support/apps'
import { createE2EResourceName } from '../../../support/naming'
import { createTestApp } from '../../../support/api/apps.ts'
import { syncMinimalWorkflowDraft } from '../../../support/api/workflows.ts'
import { waitForAppsConsole } from '../../../support/apps.ts'
import { createE2EResourceName } from '../../../support/naming.ts'
Given('a {string} app has been created via API', async function (this: DifyWorld, mode: string) {
const appMode = zCreateAppPayload.shape.mode.parse(mode)

View File

@@ -1,4 +1,4 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Given } from '@cucumber/cucumber'
Given('I am signed in as the default E2E admin', async function (this: DifyWorld) {

View File

@@ -1,8 +1,8 @@
import type { DifyWorld } from '../../support/world'
import type { DifyWorld } from '../../support/world.ts'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import { waitForAppsConsole } from '../../../support/apps'
import { waitForConsoleHome } from '../../../support/home'
import { waitForAppsConsole } from '../../../support/apps.ts'
import { waitForConsoleHome } from '../../../support/home.ts'
When('I open the default console entry', async function (this: DifyWorld) {
await this.getPage().goto('/')

View File

@@ -1,16 +1,16 @@
import type { Browser, Page } from '@playwright/test'
import type { Buffer } from 'node:buffer'
import type { CleanupTask } from '../../support/cleanup'
import type { DifyWorld } from './world'
import type { CleanupTask } from '../../support/cleanup.ts'
import type { DifyWorld } from './world.ts'
import { mkdir, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { After, AfterAll, Before, setDefaultTimeout, Status } from '@cucumber/cucumber'
import { chromium, webkit } from '@playwright/test'
import { AUTH_BOOTSTRAP_TIMEOUT_MS, ensureAuthenticatedState } from '../../fixtures/auth'
import { runCleanupTasks, shouldFailForCleanupErrors } from '../../support/cleanup'
import { getVoiceInputTestMaterialPath } from '../../support/test-materials'
import { baseURL, cucumberHeadless, cucumberSlowMo, e2eBrowser } from '../../test-env'
import { AUTH_BOOTSTRAP_TIMEOUT_MS, ensureAuthenticatedState } from '../../fixtures/auth.ts'
import { runCleanupTasks, shouldFailForCleanupErrors } from '../../support/cleanup.ts'
import { getVoiceInputTestMaterialPath } from '../../support/test-materials.ts'
import { baseURL, cucumberHeadless, cucumberSlowMo, e2eBrowser } from '../../test-env.ts'
const e2eRoot = fileURLToPath(new URL('../..', import.meta.url))
const artifactsDir = path.join(e2eRoot, 'cucumber-report', 'artifacts')

View File

@@ -1,13 +1,13 @@
import type { IWorldOptions } from '@cucumber/cucumber'
import type { APIRequestContext, Browser, BrowserContext, Download, Page } from '@playwright/test'
import type { AuthSessionMetadata } from '../../fixtures/auth'
import type { ConsoleClient } from '../../support/api/console-client'
import type { AuthSessionMetadata } from '../../fixtures/auth.ts'
import type { ConsoleClient } from '../../support/api/console-client.ts'
import { setWorldConstructor, World } from '@cucumber/cucumber'
import { request } from '@playwright/test'
import { authStatePath, readAuthSessionMetadata } from '../../fixtures/auth'
import { createConsoleClient } from '../../support/api/console-client'
import { runCleanupTasks } from '../../support/cleanup'
import { apiURL, baseURL, defaultLocale } from '../../test-env'
import { authStatePath, readAuthSessionMetadata } from '../../fixtures/auth.ts'
import { createConsoleClient } from '../../support/api/console-client.ts'
import { runCleanupTasks } from '../../support/cleanup.ts'
import { apiURL, baseURL, defaultLocale } from '../../test-env.ts'
export type ScenarioCleanup = () => Promise<void> | void
export type CreatedAgentConfigFile = {

View File

@@ -3,8 +3,8 @@ import { Buffer } from 'node:buffer'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { createConsoleClient } from '../support/api/console-client'
import { defaultBaseURL, defaultLocale } from '../test-env'
import { createConsoleClient } from '../support/api/console-client.ts'
import { defaultBaseURL, defaultLocale } from '../test-env.ts'
export type AuthSessionMetadata = {
adminEmail: string

View File

@@ -3,28 +3,28 @@
"private": true,
"type": "module",
"scripts": {
"e2e": "tsx ./scripts/run-cucumber.ts",
"e2e": "node ./scripts/run-cucumber.ts",
"e2e:accessibility": "pnpm run e2e:accessibility:aa",
"e2e:accessibility:a": "tsx ./scripts/run-cucumber.ts --full -- --tags \"@axe and @wcag-a\"",
"e2e:accessibility:aa": "tsx ./scripts/run-cucumber.ts --full -- --tags \"@axe and @wcag-aa\"",
"e2e:external": "tsx ./scripts/run-external-runtime.ts",
"e2e:external:prepare": "tsx ./scripts/run-cucumber.ts --seed-only --profile external-runtime",
"e2e:full": "tsx ./scripts/run-cucumber.ts --full",
"e2e:full:headed": "tsx ./scripts/run-cucumber.ts --full --headed",
"e2e:headed": "tsx ./scripts/run-cucumber.ts --headed",
"e2e:accessibility:a": "node ./scripts/run-cucumber.ts --full -- --tags \"@axe and @wcag-a\"",
"e2e:accessibility:aa": "node ./scripts/run-cucumber.ts --full -- --tags \"@axe and @wcag-aa\"",
"e2e:external": "node ./scripts/run-external-runtime.ts",
"e2e:external:prepare": "node ./scripts/run-cucumber.ts --seed-only --profile external-runtime",
"e2e:full": "node ./scripts/run-cucumber.ts --full",
"e2e:full:headed": "node ./scripts/run-cucumber.ts --full --headed",
"e2e:headed": "node ./scripts/run-cucumber.ts --headed",
"e2e:install": "playwright install --with-deps chromium webkit",
"e2e:install:ci": "playwright install --with-deps --only-shell chromium webkit",
"e2e:install:ci:chromium": "playwright install --with-deps --only-shell chromium",
"e2e:install:ci:webkit": "playwright install --with-deps --only-shell webkit",
"e2e:middleware:down": "tsx ./scripts/setup.ts middleware-down",
"e2e:middleware:up": "tsx ./scripts/setup.ts middleware-up",
"e2e:post-merge": "tsx ./scripts/run-post-merge.ts",
"e2e:post-merge:prepare": "tsx ./scripts/run-cucumber.ts --seed-only --profile post-merge",
"e2e:prepared": "tsx ./scripts/run-prepared.ts",
"e2e:prepared:prepare": "tsx ./scripts/run-cucumber.ts --seed-only --profile prepared",
"e2e:reset": "tsx ./scripts/setup.ts reset",
"e2e:web:build": "tsx ./scripts/setup.ts web-build",
"seed": "tsx ./scripts/run-cucumber.ts --seed-only",
"e2e:middleware:down": "node ./scripts/setup.ts middleware-down",
"e2e:middleware:up": "node ./scripts/setup.ts middleware-up",
"e2e:post-merge": "node ./scripts/run-post-merge.ts",
"e2e:post-merge:prepare": "node ./scripts/run-cucumber.ts --seed-only --profile post-merge",
"e2e:prepared": "node ./scripts/run-prepared.ts",
"e2e:prepared:prepare": "node ./scripts/run-cucumber.ts --seed-only --profile prepared",
"e2e:reset": "node ./scripts/setup.ts reset",
"e2e:web:build": "node ./scripts/setup.ts web-build",
"seed": "node ./scripts/run-cucumber.ts --seed-only",
"test:unit": "vp test run",
"type-check": "tsc"
},
@@ -41,7 +41,6 @@
"@types/node": "catalog:",
"@typescript/native": "catalog:",
"eventsource-parser": "catalog:",
"tsx": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vite-plus": "catalog:",

View File

@@ -6,7 +6,7 @@ import { access, copyFile, readFile, writeFile } from 'node:fs/promises'
import net from 'node:net'
import path from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { sleep } from '../support/process'
import { sleep } from '../support/process.ts'
type RunCommandOptions = {
command: string

View File

@@ -1,4 +1,4 @@
import { loadE2eEnv, validateE2eEnv } from './env'
import { loadE2eEnv, validateE2eEnv } from './env.ts'
// Entry points import this before test-env.ts so e2e/.env.local can affect base URLs and runner flags.
loadE2eEnv()

View File

@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs'
import path from 'node:path'
import { createEnv } from '@t3-oss/env-core'
import * as z from 'zod'
import { e2eDir } from './common'
import { e2eDir } from './common.ts'
const booleanString = z.enum(['0', '1', 'false', 'true'])
const jsonObjectString = z.string().refine((value) => {

View File

@@ -1,16 +1,16 @@
import type { ManagedProcess } from '../support/process'
import type { ManagedProcess } from '../support/process.ts'
import { mkdir, readFile, rm } from 'node:fs/promises'
import path from 'node:path'
import { runCleanupTasks } from '../support/cleanup'
import { assertCucumberScenariosStarted } from '../support/cucumber-messages'
import { startLoggedProcess, stopManagedProcess, waitForUrl } from '../support/process'
import { startWebServer, stopWebServer } from '../support/web-server'
import { apiURL, baseURL, reuseExistingWebServer } from '../test-env'
import { e2eDir, isMainModule, runCommand } from './common'
import { parseRunOptions, shouldStartManagedAgentBackend } from './run-options'
import { runSeed } from './seed-runner'
import { resetState, startMiddleware, stopMiddleware } from './setup'
import './env-register'
import { runCleanupTasks } from '../support/cleanup.ts'
import { assertCucumberScenariosStarted } from '../support/cucumber-messages.ts'
import { startLoggedProcess, stopManagedProcess, waitForUrl } from '../support/process.ts'
import { startWebServer, stopWebServer } from '../support/web-server.ts'
import { apiURL, baseURL, reuseExistingWebServer } from '../test-env.ts'
import { e2eDir, isMainModule, runCommand } from './common.ts'
import { parseRunOptions, shouldStartManagedAgentBackend } from './run-options.ts'
import { runSeed } from './seed-runner.ts'
import { resetState, startMiddleware, stopMiddleware } from './setup.ts'
import './env-register.ts'
const hasCustomTags = (forwardArgs: string[]) =>
forwardArgs.some((arg) => arg === '--tags' || arg.startsWith('--tags='))
@@ -132,7 +132,7 @@ const main = async () => {
if (startAgentBackendForRun) {
shellctlProcess = await startLoggedProcess({
command: process.execPath,
args: ['--import', 'tsx', './scripts/setup.ts', 'shellctl-sandbox'],
args: ['./scripts/setup.ts', 'shellctl-sandbox'],
cwd: e2eDir,
label: 'shellctl sandbox',
logFilePath: path.join(logDir, 'cucumber-shellctl-sandbox.log'),
@@ -146,7 +146,7 @@ const main = async () => {
difyAgentProcess = await startLoggedProcess({
command: process.execPath,
args: ['--import', 'tsx', './scripts/setup.ts', 'agent-backend'],
args: ['./scripts/setup.ts', 'agent-backend'],
cwd: e2eDir,
env: { E2E_START_AGENT_BACKEND: '1' },
label: 'agent backend',
@@ -162,7 +162,7 @@ const main = async () => {
apiProcess = await startLoggedProcess({
command: process.execPath,
args: ['--import', 'tsx', './scripts/setup.ts', 'api'],
args: ['./scripts/setup.ts', 'api'],
cwd: e2eDir,
env: startAgentBackendForRun ? { E2E_START_AGENT_BACKEND: '1' } : undefined,
label: 'api server',
@@ -176,13 +176,7 @@ const main = async () => {
celeryProcess = await startLoggedProcess({
command: process.execPath,
args: [
'--import',
'tsx',
'./scripts/setup.ts',
'celery',
...(seed ? ['--queues', seedCeleryQueues] : []),
],
args: ['./scripts/setup.ts', 'celery', ...(seed ? ['--queues', seedCeleryQueues] : [])],
cwd: e2eDir,
label: 'celery worker',
logFilePath: path.join(logDir, 'cucumber-celery.log'),
@@ -191,7 +185,7 @@ const main = async () => {
await startWebServer({
baseURL,
command: process.execPath,
args: ['--import', 'tsx', './scripts/setup.ts', 'web'],
args: ['./scripts/setup.ts', 'web'],
cwd: e2eDir,
logFilePath: path.join(logDir, 'cucumber-web.log'),
reuseExistingServer: reuseExistingWebServer,
@@ -211,8 +205,6 @@ const main = async () => {
const result = await runCommand({
command: process.execPath,
args: [
'--import',
'tsx',
'./node_modules/@cucumber/cucumber/bin/cucumber.js',
'--config',
'./cucumber.config.ts',

View File

@@ -1,5 +1,5 @@
import { e2eDir, isMainModule, runForegroundProcess } from './common'
import './env-register'
import { e2eDir, isMainModule, runForegroundProcess } from './common.ts'
import './env-register.ts'
const defaultExternalRuntimeTags = '@external-model or @external-tool'
@@ -7,8 +7,6 @@ const main = async () => {
await runForegroundProcess({
command: process.execPath,
args: [
'--import',
'tsx',
'./scripts/run-cucumber.ts',
'--full',
'--profile',

View File

@@ -1,4 +1,4 @@
import type { SeedOptions } from './seed-runner'
import type { SeedOptions } from './seed-runner.ts'
export type RunOptions = {
forwardArgs: string[]

View File

@@ -1,5 +1,5 @@
import { e2eDir, isMainModule, runForegroundProcess } from './common'
import './env-register'
import { e2eDir, isMainModule, runForegroundProcess } from './common.ts'
import './env-register.ts'
const postMergeTags = '@prepared or @external-model or @external-tool'
@@ -7,8 +7,6 @@ const main = async () => {
await runForegroundProcess({
command: process.execPath,
args: [
'--import',
'tsx',
'./scripts/run-cucumber.ts',
'--full',
'--profile',

View File

@@ -1,5 +1,5 @@
import { e2eDir, isMainModule, runForegroundProcess } from './common'
import './env-register'
import { e2eDir, isMainModule, runForegroundProcess } from './common.ts'
import './env-register.ts'
const preparedTags = '@prepared'
@@ -7,8 +7,6 @@ const main = async () => {
await runForegroundProcess({
command: process.execPath,
args: [
'--import',
'tsx',
'./scripts/run-cucumber.ts',
'--full',
'--profile',

View File

@@ -1,9 +1,9 @@
import { chromium } from '@playwright/test'
import { createAgentV2SeedTasks } from '../features/agent-v2/support/seed'
import { ensureAuthenticatedState } from '../fixtures/auth'
import { createStandaloneConsoleSession } from '../support/api/console-session'
import { runSeedTasks, writeSeedReport } from '../support/seed'
import { baseURL } from '../test-env'
import { createAgentV2SeedTasks } from '../features/agent-v2/support/seed.ts'
import { ensureAuthenticatedState } from '../fixtures/auth.ts'
import { createStandaloneConsoleSession } from '../support/api/console-session.ts'
import { runSeedTasks, writeSeedReport } from '../support/seed.ts'
import { baseURL } from '../test-env.ts'
export type SeedOptions = {
allowBlocked: boolean

View File

@@ -1,7 +1,7 @@
import { createHash } from 'node:crypto'
import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { waitForUrl } from '../support/process'
import { waitForUrl } from '../support/process.ts'
import {
apiDir,
apiEnvExampleFile,
@@ -26,8 +26,8 @@ import {
runForegroundProcess,
waitForCondition,
webDir,
} from './common'
import './env-register'
} from './common.ts'
import './env-register.ts'
const buildIdPath = path.join(webDir, '.next', 'BUILD_ID')
const webBuildStampPath = path.join(webDir, '.next', 'e2e-web-build.sha256')
@@ -569,7 +569,7 @@ export const startMiddleware = async () => {
const printUsage = () => {
console.log(
'Usage: tsx ./scripts/setup.ts <reset|middleware-up|middleware-down|shellctl-sandbox|agent-backend|api|celery [--queues queues]|web|web-build>',
'Usage: node ./scripts/setup.ts <reset|middleware-up|middleware-down|shellctl-sandbox|agent-backend|api|celery [--queues queues]|web|web-build>',
)
}

View File

@@ -1,6 +1,6 @@
import type { CreateAppPayload, PostAppsResponse } from '@dify/contracts/api/console/apps/types.gen'
import type { ConsoleClient } from './console-client'
import { assertE2EResourceName, createE2EResourceName } from '../naming'
import type { ConsoleClient } from './console-client.ts'
import { assertE2EResourceName, createE2EResourceName } from '../naming.ts'
export async function createTestApp(
client: ConsoleClient,

View File

@@ -1,13 +1,13 @@
import type { ContractRouterClient } from '@orpc/contract'
import type { JsonifiedClient } from '@orpc/openapi-client'
import type { APIRequestContext } from '@playwright/test'
import type { ConsoleClientContext } from './playwright-fetch'
import type { ConsoleClientContext } from './playwright-fetch.ts'
import { consoleRouterContract } from '@dify/contracts/api/console/router.gen'
import { createORPCClient } from '@orpc/client'
import { RequestValidationPlugin, ResponseValidationPlugin } from '@orpc/contract/plugins'
import { OpenAPILink } from '@orpc/openapi-client/fetch'
import { apiURL } from '../../test-env'
import { createPlaywrightFetch } from './playwright-fetch'
import { apiURL } from '../../test-env.ts'
import { createPlaywrightFetch } from './playwright-fetch.ts'
type ConsoleRequestContext = Pick<APIRequestContext, 'fetch' | 'storageState'>

View File

@@ -1,7 +1,7 @@
import { request } from '@playwright/test'
import { authStatePath } from '../../fixtures/auth'
import { apiURL } from '../../test-env'
import { createConsoleClient } from './console-client'
import { authStatePath } from '../../fixtures/auth.ts'
import { apiURL } from '../../test-env.ts'
import { createConsoleClient } from './console-client.ts'
export async function createStandaloneConsoleSession() {
const requestContext = await request.newContext({

View File

@@ -1,5 +1,5 @@
import type { SyncDraftWorkflowPayload } from '@dify/contracts/api/console/apps/types.gen'
import type { ConsoleClient } from './console-client'
import type { ConsoleClient } from './console-client.ts'
export async function syncMinimalWorkflowDraft(
client: ConsoleClient,

View File

@@ -1,10 +1,10 @@
import type { PluginInstallTask } from '@dify/contracts/api/console/workspaces/types.gen'
import type { ConsoleClient } from './api/console-client'
import type { SeedContext, SeedResult } from './seed'
import type { ConsoleClient } from './api/console-client.ts'
import type { SeedContext, SeedResult } from './seed.ts'
import { Buffer } from 'node:buffer'
import { ORPCError } from '@orpc/client'
import { sleep } from './process'
import { blocked, created, skipped, verified } from './seed'
import { sleep } from './process.ts'
import { blocked, created, skipped, verified } from './seed.ts'
type MarketplacePluginBootstrapConfig = {
defaultPluginIds: string[]

View File

@@ -1,7 +1,7 @@
import type { ConsoleClient } from './api/console-client'
import type { ConsoleClient } from './api/console-client.ts'
import { mkdir, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { e2eDir } from '../scripts/common'
import { e2eDir } from '../scripts/common.ts'
export type SeedStatus = 'blocked' | 'created' | 'skipped' | 'updated' | 'verified'

View File

@@ -1,5 +1,5 @@
import type { ManagedProcess } from './process'
import { isPortReachable, startLoggedProcess, stopManagedProcess, waitForUrl } from './process'
import type { ManagedProcess } from './process.ts'
import { isPortReachable, startLoggedProcess, stopManagedProcess, waitForUrl } from './process.ts'
type WebServerStartOptions = {
baseURL: string

View File

@@ -1,4 +1,4 @@
import './scripts/env-register'
import './scripts/env-register.ts'
export const defaultBaseURL = 'http://127.0.0.1:3000'
export const defaultApiURL = 'http://127.0.0.1:5001'

View File

@@ -1,6 +1,6 @@
import type { DifyWorld } from '../features/support/world'
import type { DifyWorld } from '../features/support/world.ts'
import { afterEach, describe, expect, it, vi } from 'vite-plus/test'
import { requireAgentBackendRuntime } from '../features/agent-v2/support/fixtures/agent-backend'
import { requireAgentBackendRuntime } from '../features/agent-v2/support/fixtures/agent-backend.ts'
describe('requireAgentBackendRuntime', () => {
afterEach(() => {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vite-plus/test'
import { createAgentV2SeedTasks } from '../features/agent-v2/support/seed'
import { createAgentV2SeedTasks } from '../features/agent-v2/support/seed.ts'
const baseTaskIds = [
'marketplace-plugins',

View File

@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from 'vite-plus/test'
import { runCleanupTasks, shouldFailForCleanupErrors } from '../support/cleanup'
import { runCleanupTasks, shouldFailForCleanupErrors } from '../support/cleanup.ts'
describe('runCleanupTasks', () => {
it('runs every task in order', async () => {

View File

@@ -1,8 +1,8 @@
import type { APIRequestContext, APIResponse } from '@playwright/test'
import { Buffer } from 'node:buffer'
import { describe, expect, it, vi } from 'vite-plus/test'
import { createConsoleClient } from '../support/api/console-client'
import { createPlaywrightFetch } from '../support/api/playwright-fetch'
import { createConsoleClient } from '../support/api/console-client.ts'
import { createPlaywrightFetch } from '../support/api/playwright-fetch.ts'
const createApiResponse = ({
body = '',

View File

@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vite-plus/test'
import {
assertCucumberScenariosStarted,
countStartedCucumberScenarios,
} from '../support/cucumber-messages'
} from '../support/cucumber-messages.ts'
describe('countStartedCucumberScenarios', () => {
it('counts test case start messages', () => {

View File

@@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from 'vite-plus/test'
import { getAgentBackendEnvironment } from '../scripts/setup'
import { getAgentBackendEnvironment } from '../scripts/setup.ts'
describe('managed runtime environment', () => {
afterEach(() => {

View File

@@ -1,7 +1,7 @@
import type { ConsoleClient } from '../support/api/console-client'
import type { ConsoleClient } from '../support/api/console-client.ts'
import { ORPCError } from '@orpc/client'
import { afterEach, describe, expect, it, vi } from 'vite-plus/test'
import { bootstrapMarketplacePlugins } from '../support/marketplace-plugins'
import { bootstrapMarketplacePlugins } from '../support/marketplace-plugins.ts'
const createMarketplaceConsoleClient = (installError: unknown) => {
const installMarketplace = vi.fn().mockRejectedValue(installError)

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vite-plus/test'
import { parseRunOptions, shouldStartManagedAgentBackend } from '../scripts/run-options'
import { parseRunOptions, shouldStartManagedAgentBackend } from '../scripts/run-options.ts'
describe('E2E run options', () => {
it('forwards Cucumber arguments without requesting seed data', () => {

View File

@@ -1,6 +1,6 @@
import assert from 'node:assert/strict'
import { describe, it } from 'vite-plus/test'
import { consumeServiceApiSse } from '../features/agent-v2/support/service-api-sse'
import { consumeServiceApiSse } from '../features/agent-v2/support/service-api-sse.ts'
const encodeChunks = (text: string, splitPoints: number[]) => {
const bytes = new TextEncoder().encode(text)

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vite-plus/test'
import { resolveE2EBrowser } from '../test-env'
import { resolveE2EBrowser } from '../test-env.ts'
describe('resolveE2EBrowser', () => {
it('uses Chromium by default', () => {

View File

@@ -2,7 +2,10 @@
"extends": "@dify/tsconfig/node.json",
"compilerOptions": {
"lib": ["ES2023", "DOM"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"types": ["node", "@playwright/test", "@cucumber/cucumber"],
"allowImportingTsExtensions": true,
"allowJs": false,
"verbatimModuleSyntax": true
},

View File

@@ -1,3 +0,0 @@
import { register } from 'tsx/esm/api'
register()

View File

@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vite-plus/test'
import {
zAccountPasswordPayload,
zAccountProfilePatchPayload,
} from './generated/api/console/account/zod.gen'
} from './generated/api/console/account/zod.gen.ts'
describe('generated account profile schema', () => {
it('matches the server rules for partial updates', () => {

View File

@@ -2,9 +2,9 @@ import { describe, expect, it } from 'vite-plus/test'
import {
zGetAppsByAppIdExportResponse,
zPostAppsImportsBody,
} from './generated/api/console/apps/zod.gen'
import { zPostFilesUploadBody } from './generated/api/console/files/zod.gen'
import { zPostWorkspacesCurrentPluginUploadPkgBody } from './generated/api/console/workspaces/zod.gen'
} from './generated/api/console/apps/zod.gen.ts'
import { zPostFilesUploadBody } from './generated/api/console/files/zod.gen.ts'
import { zPostWorkspacesCurrentPluginUploadPkgBody } from './generated/api/console/workspaces/zod.gen.ts'
describe('generated binary schemas', () => {
it('accepts binary package imports alongside YAML import requests', () => {

View File

@@ -1,6 +1,6 @@
import { consoleRouterContract as generatedConsoleRouterContract } from './generated/api/console/router.gen'
import { contract as enterpriseAppDeployContract } from './generated/enterprise-app-deploy/orpc.gen'
import { contract as knowledgeFsContract } from './generated/knowledge-fs/orpc.gen'
import { consoleRouterContract as generatedConsoleRouterContract } from './generated/api/console/router.gen.ts'
import { contract as enterpriseAppDeployContract } from './generated/enterprise-app-deploy/orpc.gen.ts'
import { contract as knowledgeFsContract } from './generated/knowledge-fs/orpc.gen.ts'
export const consoleRouterContract = {
...generatedConsoleRouterContract,

View File

@@ -42,7 +42,7 @@ import {
zPostAccountPasswordResponse,
zPostAccountTimezoneBody,
zPostAccountTimezoneResponse,
} from './zod.gen'
} from './zod.gen.ts'
/**
* Get account avatar url

View File

@@ -7,7 +7,7 @@ import {
zGetActivateCheckResponse,
zPostActivateBody,
zPostActivateResponse,
} from './zod.gen'
} from './zod.gen.ts'
/**
* Check if activation token is valid

View File

@@ -157,7 +157,7 @@ import {
zPutAgentByAgentIdComposerResponse,
zPutAgentByAgentIdPath,
zPutAgentByAgentIdResponse,
} from './zod.gen'
} from './zod.gen.ts'
export const get = oc
.route({

View File

@@ -2,7 +2,7 @@
import { oc } from '@orpc/contract'
import * as z from 'zod'
import { zGetAllWorkspacesQuery, zGetAllWorkspacesResponse } from './zod.gen'
import { zGetAllWorkspacesQuery, zGetAllWorkspacesResponse } from './zod.gen.ts'
export const get = oc
.route({

Some files were not shown because too many files have changed in this diff Show More