We are using YouTrack as our task tracker and knowledge base and we were interested in using also for test cases management. JetBrains blog has a nice article explaining how to setup the flow and workflows code that you can import in your instance.
However, we noticed that when you create a Test Run, and attach Test Suite (with a number of Test Cases), Test Case Executing is created for Test Suite. We expected the system to create a Test Case Execution for each Test Case in the Test Suite. For example
To achieve this, we slightly modified populate-test-run.js to look like this
/** * This is a template for an on-change rule. This rule defines what * happens when a change is applied to an issue. * * For details, read the Quick Start Guide: * https://www.jetbrains.com/help/youtrack/incloud/2020.3/Quick-Start-Guide-Workflows-JS.html */ var entities = require('@jetbrains/youtrack-scripting-api/entities'); var workflow = require('@jetbrains/youtrack-scripting-api/workflow'); function createExecutionIssues(TestCase, ctx, testRun) { var TestCaseRun = TestCase.copy(); TestCaseRun.Type = ctx.Type.TestExecution.name; TestCaseRun.Status = ctx.Status.NoRun.name; // Remove all links from Test Case Execution Object.keys(TestCaseRun.links).forEach(function (linkType) { if (!TestCaseRun.links[linkType]) return; TestCaseRun.links[linkType].clear(); }); TestCaseRun.summary = "[TEST_CASE_EXECUTION" + "] [" + TestCaseRun.summary + "]"; // Links population TestCaseRun.links[ctx.Subtask.inward].add(testRun); testRun.links[ctx.Subtask.outward].add(TestCaseRun); TestCaseRun.links[ctx.Execution.outward].add(TestCase); } function createRecursive(TestSuite, ctx, parent) { TestSuite.links[ctx.Subtask.outward].forEach(childSuite => { if (childSuite.Type.name !== ctx.Type.TestSuite.name) return; createRecursive(childSuite, ctx, parent); }); // New issue creation TestSuite.links[ctx.Subtask.outward].forEach(testCase => { if (testCase.Type.name !== ctx.Type.TestCase.name) return; createExecutionIssues(testCase, ctx, parent); }); } exports.rule = entities.Issue.onChange({ title: 'Populate-test-run', guard: function (ctx) { var issue = ctx.issue; return !issue.isChanged('project') && issue.Type && (issue.Type.name == ctx.Type.TestRun.name) && issue.links[ctx.Execution.outward].added.isNotEmpty() && issue.isReported; }, action: function (ctx) { var testRun = ctx.issue; var totalTestRuns = testRun.links[ctx.Execution.outward].added.size; testRun.links[ctx.Execution.outward].added.forEach(function (TestCase) { var message = '<a href="' + TestCase.url + '"> ' + TestCase.id + '</a>'; workflow.check((TestCase.Type.name === ctx.Type.TestCase.name) || (TestCase.Type.name === ctx.Type.TestSuite.name), workflow.i18n('\'Test Run\' can be linked to \'Test Case\' and \'Test Suite\' only, but {0} has \'{1}\' type!', message, TestCase.Type.name)); TestCase.links[ctx.Execution.inward].delete(testRun); if (TestCase.Type.name === ctx.Type.TestSuite.name) { createRecursive(TestCase, ctx, testRun); return; } createExecutionIssues(TestCase, ctx, testRun); }); testRun.fields['Total number of test cases'] = totalTestRuns; }, requirements: { Execution: { type: entities.IssueLinkPrototype, name: 'Execution', inward: 'Execution', outward: 'Assigned test case or test suite' }, Subtask: { type: entities.IssueLinkPrototype, name: 'Subtask', inward: 'parent for', outward: 'subtask of' }, Type: { type: entities.EnumField.fieldType, TestExecution: { name: "Test Case Execution" }, TestRun: { name: "Test Run" }, TestCase: { name: "Test Case" }, TestSuite: { name: "Test Suite" } }, Total: { type: entities.Field.integerType, name: 'Total number of test cases' }, TotalFailed: { type: entities.Field.integerType, name: 'Number of failed test cases' }, TotalPassed: { type: entities.Field.integerType, name: 'Number of passed test cases' }, Status: { type: entities.EnumField.fieldType, InProgress: { name: 'In Progress' }, Passed: { name: 'Passed' }, Failed: { name: 'Failed' }, NoRun: { name: 'No Run' }, }, } });
The important bits are
createExecutionIssues
and createRecursive
functions, which create executions for all test cases recursively.