|
|
|
@@ -0,0 +1,207 @@ |
|
|
|
/** |
|
|
|
* Test cases to reproduce the plugin tool workflow error |
|
|
|
* Issue: #23154 - Application error when loading plugin tools in workflow |
|
|
|
* Root cause: split() operation called on null/undefined values |
|
|
|
*/ |
|
|
|
|
|
|
|
describe('Plugin Tool Workflow Error Reproduction', () => { |
|
|
|
/** |
|
|
|
* Mock function to simulate the problematic code in switch-plugin-version.tsx:29 |
|
|
|
* const [pluginId] = uniqueIdentifier.split(':') |
|
|
|
*/ |
|
|
|
const mockSwitchPluginVersionLogic = (uniqueIdentifier: string | null | undefined) => { |
|
|
|
// This directly reproduces the problematic line from switch-plugin-version.tsx:29 |
|
|
|
const [pluginId] = uniqueIdentifier!.split(':') |
|
|
|
return pluginId |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 1: Simulate null uniqueIdentifier |
|
|
|
* This should reproduce the error mentioned in the issue |
|
|
|
*/ |
|
|
|
it('should reproduce error when uniqueIdentifier is null', () => { |
|
|
|
expect(() => { |
|
|
|
mockSwitchPluginVersionLogic(null) |
|
|
|
}).toThrow('Cannot read properties of null (reading \'split\')') |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 2: Simulate undefined uniqueIdentifier |
|
|
|
*/ |
|
|
|
it('should reproduce error when uniqueIdentifier is undefined', () => { |
|
|
|
expect(() => { |
|
|
|
mockSwitchPluginVersionLogic(undefined) |
|
|
|
}).toThrow('Cannot read properties of undefined (reading \'split\')') |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 3: Simulate empty string uniqueIdentifier |
|
|
|
*/ |
|
|
|
it('should handle empty string uniqueIdentifier', () => { |
|
|
|
expect(() => { |
|
|
|
const result = mockSwitchPluginVersionLogic('') |
|
|
|
expect(result).toBe('') // Empty string split by ':' returns [''] |
|
|
|
}).not.toThrow() |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 4: Simulate malformed uniqueIdentifier without colon separator |
|
|
|
*/ |
|
|
|
it('should handle malformed uniqueIdentifier without colon separator', () => { |
|
|
|
expect(() => { |
|
|
|
const result = mockSwitchPluginVersionLogic('malformed-identifier-without-colon') |
|
|
|
expect(result).toBe('malformed-identifier-without-colon') // No colon means full string returned |
|
|
|
}).not.toThrow() |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 5: Simulate valid uniqueIdentifier |
|
|
|
*/ |
|
|
|
it('should work correctly with valid uniqueIdentifier', () => { |
|
|
|
expect(() => { |
|
|
|
const result = mockSwitchPluginVersionLogic('valid-plugin-id:1.0.0') |
|
|
|
expect(result).toBe('valid-plugin-id') |
|
|
|
}).not.toThrow() |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test for the variable processing split error in use-single-run-form-params |
|
|
|
*/ |
|
|
|
describe('Variable Processing Split Error', () => { |
|
|
|
/** |
|
|
|
* Mock function to simulate the problematic code in use-single-run-form-params.ts:91 |
|
|
|
* const getDependentVars = () => { |
|
|
|
* return varInputs.map(item => item.variable.slice(1, -1).split('.')) |
|
|
|
* } |
|
|
|
*/ |
|
|
|
const mockGetDependentVars = (varInputs: Array<{ variable: string | null | undefined }>) => { |
|
|
|
return varInputs.map((item) => { |
|
|
|
// Guard against null/undefined variable to prevent app crash |
|
|
|
if (!item.variable || typeof item.variable !== 'string') |
|
|
|
return [] |
|
|
|
|
|
|
|
return item.variable.slice(1, -1).split('.') |
|
|
|
}).filter(arr => arr.length > 0) // Filter out empty arrays |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 1: Variable processing with null variable |
|
|
|
*/ |
|
|
|
it('should handle null variable safely', () => { |
|
|
|
const varInputs = [{ variable: null }] |
|
|
|
|
|
|
|
expect(() => { |
|
|
|
mockGetDependentVars(varInputs) |
|
|
|
}).not.toThrow() |
|
|
|
|
|
|
|
const result = mockGetDependentVars(varInputs) |
|
|
|
expect(result).toEqual([]) // null variables are filtered out |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 2: Variable processing with undefined variable |
|
|
|
*/ |
|
|
|
it('should handle undefined variable safely', () => { |
|
|
|
const varInputs = [{ variable: undefined }] |
|
|
|
|
|
|
|
expect(() => { |
|
|
|
mockGetDependentVars(varInputs) |
|
|
|
}).not.toThrow() |
|
|
|
|
|
|
|
const result = mockGetDependentVars(varInputs) |
|
|
|
expect(result).toEqual([]) // undefined variables are filtered out |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 3: Variable processing with empty string |
|
|
|
*/ |
|
|
|
it('should handle empty string variable', () => { |
|
|
|
const varInputs = [{ variable: '' }] |
|
|
|
|
|
|
|
expect(() => { |
|
|
|
mockGetDependentVars(varInputs) |
|
|
|
}).not.toThrow() |
|
|
|
|
|
|
|
const result = mockGetDependentVars(varInputs) |
|
|
|
expect(result).toEqual([]) // Empty string is filtered out, so result is empty array |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test case 4: Variable processing with valid variable format |
|
|
|
*/ |
|
|
|
it('should work correctly with valid variable format', () => { |
|
|
|
const varInputs = [{ variable: '{{workflow.node.output}}' }] |
|
|
|
|
|
|
|
expect(() => { |
|
|
|
mockGetDependentVars(varInputs) |
|
|
|
}).not.toThrow() |
|
|
|
|
|
|
|
const result = mockGetDependentVars(varInputs) |
|
|
|
expect(result[0]).toEqual(['{workflow', 'node', 'output}']) |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Integration test to simulate the complete workflow scenario |
|
|
|
*/ |
|
|
|
describe('Plugin Tool Workflow Integration', () => { |
|
|
|
/** |
|
|
|
* Simulate the scenario where plugin metadata is incomplete or corrupted |
|
|
|
* This can happen when: |
|
|
|
* 1. Plugin is being loaded from marketplace but metadata request fails |
|
|
|
* 2. Plugin configuration is corrupted in database |
|
|
|
* 3. Network issues during plugin loading |
|
|
|
*/ |
|
|
|
it('should reproduce the client-side exception scenario', () => { |
|
|
|
// Mock incomplete plugin data that could cause the error |
|
|
|
const incompletePluginData = { |
|
|
|
// Missing or null uniqueIdentifier |
|
|
|
uniqueIdentifier: null, |
|
|
|
meta: null, |
|
|
|
minimum_dify_version: undefined, |
|
|
|
} |
|
|
|
|
|
|
|
// This simulates the error path that leads to the white screen |
|
|
|
expect(() => { |
|
|
|
// Simulate the code path in switch-plugin-version.tsx:29 |
|
|
|
// The actual problematic code doesn't use optional chaining |
|
|
|
const _pluginId = (incompletePluginData.uniqueIdentifier as any).split(':')[0] |
|
|
|
}).toThrow('Cannot read properties of null (reading \'split\')') |
|
|
|
}) |
|
|
|
|
|
|
|
/** |
|
|
|
* Test the scenario mentioned in the issue where plugin tools are loaded in workflow |
|
|
|
*/ |
|
|
|
it('should simulate plugin tool loading in workflow context', () => { |
|
|
|
// Mock the workflow context where plugin tools are being loaded |
|
|
|
const workflowPluginTools = [ |
|
|
|
{ |
|
|
|
provider_name: 'test-plugin', |
|
|
|
uniqueIdentifier: null, // This is the problematic case |
|
|
|
tool_name: 'test-tool', |
|
|
|
}, |
|
|
|
{ |
|
|
|
provider_name: 'valid-plugin', |
|
|
|
uniqueIdentifier: 'valid-plugin:1.0.0', |
|
|
|
tool_name: 'valid-tool', |
|
|
|
}, |
|
|
|
] |
|
|
|
|
|
|
|
// Process each plugin tool |
|
|
|
workflowPluginTools.forEach((tool, _index) => { |
|
|
|
if (tool.uniqueIdentifier === null) { |
|
|
|
// This reproduces the exact error scenario |
|
|
|
expect(() => { |
|
|
|
const _pluginId = (tool.uniqueIdentifier as any).split(':')[0] |
|
|
|
}).toThrow() |
|
|
|
} |
|
|
|
else { |
|
|
|
// Valid tools should work fine |
|
|
|
expect(() => { |
|
|
|
const _pluginId = tool.uniqueIdentifier.split(':')[0] |
|
|
|
}).not.toThrow() |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
}) |