{"id":98669,"date":"2020-11-27T18:13:36","date_gmt":"2020-11-27T17:13:36","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=youtrack&#038;p=98669"},"modified":"2020-11-27T18:13:36","modified_gmt":"2020-11-27T17:13:36","slug":"make-it-workflow-parte-13-suporte-a-cenarios-de-gerenciamento-de-testes","status":"publish","type":"youtrack","link":"https:\/\/blog.jetbrains.com\/pt-br\/youtrack\/2020\/11\/make-it-workflow-parte-13-suporte-a-cenarios-de-gerenciamento-de-testes\/","title":{"rendered":"Make It Workflow \u2014 Parte 13: Suporte a cen\u00e1rios de gerenciamento de testes"},"content":{"rendered":"<p><a href=\"https:\/\/blog.jetbrains.com\/youtrack\/2020\/10\/make-it-workflow-part-13-supporting-test-management-scenarios\/\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/YT_workflow_en-1.png\" alt=\"\" \/><\/a><\/p>\n<p>Bem-vindo de volta \u00e0 nossa s\u00e9rie Make It Workflow! Recebemos v\u00e1rias solicita\u00e7\u00f5es da comunidade para discutir os recursos do YouTrack que podem ser utilizados pela equipe de controle de qualidade. Hoje, gostar\u00edamos de direcionar nossa aten\u00e7\u00e3o a como manter cen\u00e1rios de gerenciamento de testes (TMS) no YouTrack. Este artigo demonstrar\u00e1 como o YouTrack pode ser configurado para que voc\u00ea possa manter a funcionalidade de gerenciamento de testes dentro do pr\u00f3prio YouTrack, evitando assim o uso de solu\u00e7\u00f5es de terceiros. Essa abordagem ajuda a economizar em custos de licen\u00e7a e torna o fluxo do processo de gerenciamento de testes mais uniforme.<\/p>\n<p>Este artigo \u00e9 para gerentes de teste e qualquer pessoa interessada em workflows do YouTrack. Voc\u00ea encontrar\u00e1 um exemplo pr\u00e1tico de como criar um processo de teste no YouTrack, com recomenda\u00e7\u00f5es para configura\u00e7\u00f5es de projetos e issues, uma descri\u00e7\u00e3o de como implementar cen\u00e1rios de gerenciamento de testes e muito mais.<\/p>\n<p><span id=\"more-77371\"><\/span><\/p>\n<p>Tamb\u00e9m selecionamos uma lista de blocos de c\u00f3digo de workflow prontos para uso que podem ser aplicados para automatizar os processos de gerenciamento de testes. Esses blocos de c\u00f3digo tornam mais f\u00e1cil associar casos de teste a uma execu\u00e7\u00e3o de teste espec\u00edfica, clonar essa execu\u00e7\u00e3o de teste, exibir sugest\u00f5es do sistema no pr\u00f3ximo teste e muito mais.<br \/>\n<a name=\"ref1\"><\/a><\/p>\n<h2>Configura\u00e7\u00f5es para projetos de gerenciamento de testes no YouTrack<\/h2>\n<p>Talvez voc\u00ea queira usar tipos de issues espec\u00edficos de gerenciamento de testes para seus projetos de gerenciamento de testes, como Caso de Teste, Conjunto de Testes (um conjunto de casos de teste), Execu\u00e7\u00e3o de Teste (um conjunto de casos de teste ou conjuntos de testes atribu\u00eddos a um ciclo de teste espec\u00edfico) e Execu\u00e7\u00f5es de Casos de Teste atribu\u00eddas a uma execu\u00e7\u00e3o de teste espec\u00edfica. Voc\u00ea deve<a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/Manage-Custom-Fields-Per-Project.html#add-custom-field-to-project\" target=\"_blank\" rel=\"noopener\"> configurar<\/a> os tipos de issues necess\u00e1rios para seu projeto de TMS. Existem 3 tipos de <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/Link-Types.html\" target=\"_blank\" rel=\"noopener\">links de issues<\/a> para estabelecer conex\u00f5es e relev\u00e2ncia entre suas tarefas de gerenciamento de testes:<\/p>\n<ul>\n<li>&#8220;Parent-subtasks&#8221; padr\u00e3o mant\u00eam passagens de testes e execu\u00e7\u00f5es de casos de teste, bem como o conjunto de testes e rela\u00e7\u00f5es de casos de teste. <\/li>\n<li>&#8220;Execution&#8221; personalizada mant\u00e9m rela\u00e7\u00f5es de casos de teste e de execu\u00e7\u00f5es de casos de teste. <\/li>\n<li>&#8220;Related Bug&#8221; personalizado mant\u00e9m as rela\u00e7\u00f5es entre os testes que falharam e os bugs atribu\u00eddos.<\/li>\n<\/ul>\n<p>Os requisitos de testes podem ser mantidos como um <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/create-articles.html\" target=\"_blank\" rel=\"noopener\"> artigo<\/a> vinculado aos issues em um campo de texto.<br \/>\nAl\u00e9m disso, para as suas tarefas de gerenciamento de testes, voc\u00ea pode querer configurar <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/Manage-Custom-Fields-Per-Project.html#add-custom-field-to-project\" target=\"_blank\" rel=\"noopener\"> campos personalizados<\/a>, como <em>Test mode<\/em>, <em>Category<\/em>, <em>Test flow<\/em> e <em>Application<\/em>, juntamente com valores predefinidos (por exemplo, status de teste predefinidos). Voc\u00ea tamb\u00e9m pode usar <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/conditional-custom-fields.html\" target=\"_blank\" rel=\"noopener\"> campos condicionais<\/a> quando precisa exibir informa\u00e7\u00f5es especificamente para um tipo de issue.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS0_1.png\" alt=\"\" \/><\/p>\n<p>Um conjunto de campos predefinidos para os tipos de problemas \u201cTest Case\u201d e \u201cTest Run\u201d pode ser ajustado de acordo com as necessidades da sua empresa.<\/p>\n<h2>Configurar passagens de testes e execu\u00e7\u00e3o de testes<\/h2>\n<p>Quando, por exemplo, queremos testar uma vers\u00e3o de produto espec\u00edfica, precisamos criar uma passagem de teste e atribuir uma s\u00e9rie de conjuntos de teste e casos de teste relevantes a ela. Aqui est\u00e3o as etapas para fazer isso:<\/p>\n<ul>\n<li>Crie um issue com o tipo de issue &#8220;Test Run&#8221;. <\/li>\n<li>Use the \u2018Assigned test case and test suite\u2019 custom link type to link to the issue.<\/li>\n<li>Na janela pop-up, especifique os casos de teste que voc\u00ea gostaria de incluir na passagem de teste.<\/li>\n<\/ul>\n<p>As etapas do workflow &#8220;Populate Test Run&#8221; para preencher uma passagem de teste economizar\u00e3o tempo e esfor\u00e7os da sua equipe de controle de qualidade:<\/p>\n<ul>\n<li>C\u00f3pias de todos os conjuntos de teste e casos de teste selecionados ser\u00e3o criadas no sistema. Todos os issues ter\u00e3o o tipo de issue &#8220;Test Case Execution&#8221;. <\/li>\n<li>O tipo de link &#8220;Execution&#8221; conectar\u00e1 as execu\u00e7\u00f5es dos casos de teste aos casos de teste selecionados.<\/li>\n<li>Issues rec\u00e9m-criados ser\u00e3o vinculados \u00e0 passagem de teste como um issue pai e suas subtarefas relacionadas.<\/li>\n<\/ul>\n<p>\u00c9 assim que funciona:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done1s720cut.gif\" alt=\"\" \/><\/p>\n<details>\n<summary>\n        Expanda o bloco de c\u00f3digo<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\nvar entities = require(&#039;@jetbrains\/youtrack-scripting-api\/entities&#039;);\nvar workflow = require(&#039;@jetbrains\/youtrack-scripting-api\/workflow&#039;);\n\nexports.rule = entities.Issue.onChange({\n  title: &#039;Populate-test-run&#039;,\n  guard: function(ctx) {\n    var issue = ctx.issue;\n    return !issue.isChanged(&#039;project&#039;) &amp;&amp; issue.Type &amp;&amp; (issue.Type.name == ctx.Type.TestRun.name) &amp;&amp; issue.links[ctx.Execution.outward].added.isNotEmpty() &amp;&amp; issue.isReported;\n  },\n  action: function(ctx) {\n    var issue = ctx.issue;\n    var totalTestRuns = issue.links[ctx.Execution.outward].added.size;\n    issue.links[ctx.Execution.outward].added.forEach(function(TestCase) {\n      TestCase.links[ctx.Execution.inward].delete(issue);\n\n      var TestCaseRun = TestCase.copy();\n      TestCaseRun.Type = ctx.Type.TestExecution.name;\n      TestCaseRun.Status = ctx.Status.NoRun.name;\n      Object.keys(TestCaseRun.links).forEach(function(linkType) {\n       if (!TestCaseRun.links[linkType])\n        return;\n         TestCaseRun.links[linkType].clear();\n      });\n      TestCaseRun.summary = &quot;[TEST_CASE_EXECUTION&quot; + &quot;] [&quot; + TestCaseRun.summary + &quot;]&quot;;\n\n      TestCaseRun.links[ctx.Subtask.inward].add(issue);\n      issue.links[ctx.Subtask.outward].add(TestCaseRun);\n      TestCaseRun.links[ctx.Execution.outward].add(TestCase);\n    });\n    issue.fields[&#039;Total number of test cases&#039;] = totalTestRuns;\n  },\n  requirements: {\n    Execution: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Execution&#039;,\n      inward: &#039;Execution&#039;,\n      outward: &#039;Assigned test case or test suite&#039;\n    },\n    Subtask: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Subtask&#039;,\n      inward: &#039;parent for&#039;,\n      outward: &#039;subtask of&#039;\n    },\n    Type: {\n      type: entities.EnumField.fieldType,\n      TestExecution: {\n        name: &quot;Test Case Execution&quot;\n      },\n      TestRun: {\n        name: &quot;Test Run&quot;\n      },\n      TestCase: {\n        name: &quot;Test Case&quot;\n      },\n      TestSuite: {\n        name: &quot;Test Suite&quot;\n      }\n    },\n    Total: {\n      type: entities.Field.integerType,\n      name: &#039;Total number of test cases&#039;\n    },\n    TotalFailed: {\n      type: entities.Field.integerType,\n      name: &#039;Number of failed test cases&#039;\n    },\n    TotalPassed: {\n      type: entities.Field.integerType,\n      name: &#039;Number of passed test cases&#039;\n    },\n    Status: {\n      type: entities.EnumField.fieldType,\n      InProgress: {\n        name: &#039;In Progress&#039;\n      },\n      Passed: {\n        name: &#039;Passed&#039;\n      },\n      Failed: {\n        name: &#039;Failed&#039;\n      },\n      NoRun: {\n        name: &#039;No Run&#039;\n      },\n    },\n  }\n});\n<\/pre>\n<p>\n<\/details>\n<h2>Manuten\u00e7\u00e3o de atividades de teste<\/h2>\n<p>Depois que as passagens de testes estiverem totalmente configuradas, um engenheiro de teste poder\u00e1 iniciar os testes. Por padr\u00e3o, todos os issues com os tipos &#8220;Test Case Execution&#8221; e &#8220;Test Run&#8221; t\u00eam o status &#8220;No Run&#8221;.<\/p>\n<h3>Como alternar entre testes<\/h3>\n<p>Quando voc\u00ea est\u00e1 trabalhando com um conjunto de testes, existem duas maneiras de alternar de um teste para outro:<\/p>\n<ol>\n<li>Altere manualmente o status do teste na p\u00e1gina da lista de issues. <\/li>\n<li>Abra um teste e mude para o pr\u00f3ximo teste n\u00e3o conclu\u00eddo. When you want to switch tests in this way, a helpful pop-up appears that suggests the next test to run.<br \/>\n    The following actions can be automated:<\/p>\n<ul>\n<li> Verifique se h\u00e1 testes com o status &#8220;No Run&#8217; e pertencem \u00e0 mesma passagem de teste.<\/li>\n<li> Exiba uma mensagem com a URL do pr\u00f3ximo teste dispon\u00edvel (se houver).\n<p>    <a href=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done3s720.gif\" rel=\"attachment wp-att-6366 noopener\" target=\"_blank\"><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done3s720.gif\" alt=\"ApplyingCommandForSubsystem\"  \/><\/a><\/li>\n<\/ul>\n<p> Isso pode ser implementado usando o c\u00f3digo abaixo.<\/p>\n<details>\n<summary>\n        Expanda o bloco de c\u00f3digo<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n action: function(ctx) {\n  var issue = ctx.issue;\n  if (!issue.links[&#039;subtask of&#039;].isEmpty()) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;&lt;a href=&quot;&#039; + resultSet.url + &#039;&quot;&gt; &#039; + resultSet.id + &#039;&lt;\/a&gt;&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n    }\n}\n}\n<\/pre>\n<p>\n<\/details>\n<\/ol>\n<h2>Status de testes <\/h2>\n<p><a name=\"ref2\"><\/a><\/p>\n<p>Ao alternar de um teste para outro, um engenheiro de teste pode indicar que o teste foi aprovado (&#8220;Passed&#8221;) ou alterar o status do teste para reprovado (&#8220;Failed&#8221;) (caso um bug tenha sido identificado durante a execu\u00e7\u00e3o do caso de teste). Com base nas <a href=\"#ref1\">configura\u00e7\u00f5es do YouTrack<\/a> que inicialmente configuramos para esse projeto, existem v\u00e1rios status de passagem de teste predefinidos:<\/p>\n<ul>\n<li>Failing: pelo menos um dos testes associados tem o status &#8220;No run&#8221; e pelo menos um dos testes associados tem o status &#8220;Failed&#8221;.<\/li>\n<li>Passing: pelo menos um dos testes associados tem o status &#8220;No run&#8221; e n\u00e3o h\u00e1 testes associados com o status &#8220;Failed&#8221;.<\/li>\n<li>Failed: nenhum teste associado tem o status &#8220;No run&#8221; e pelo menos um dos testes associados tem o status &#8220;Failed&#8221;.<\/li>\n<li>Passed: nenhum teste associado tem o status &#8220;No Run&#8221; ou &#8220;Failed&#8221;.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done2s720.gif\" alt=\"\" \/><\/p>\n<p>Os status listados acima podem ajudar sua equipe de controle de qualidade a monitorar o progresso dos testes durante todo o ciclo de testes. \u00c9 importante observar que o status da passagem de teste depende apenas dos testes associados e n\u00e3o deve ser alterado manualmente. O processo para determinar o status da passagem de teste \u00e9 implementado com o uso do workflow <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/state-machine-per-issue-type.html#state-machine-per-issue-type2\" target=\"_blank\" rel=\"noopener\"> state-machines per issue type<\/a>. O bloco de c\u00f3digo de op\u00e7\u00f5es de testes tamb\u00e9m est\u00e1 incorporado no workflow.<\/p>\n<details>\n<summary>\n        Expanda o bloco de c\u00f3digo<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n\nvar entities = require(&#039;@jetbrains\/youtrack-scripting-api\/entities&#039;);\nvar workflow = require(&#039;@jetbrains\/youtrack-scripting-api\/workflow&#039;);\n\nexports.rule = entities.Issue.stateMachine({\n  title: &#039;status-management&#039;,\n  stateFieldName: &#039;Status&#039;,\n  typeFieldName: &#039;Type&#039;,\n  defaultMachine: {\n    &#039;No Run&#039;: {\n      initial: true,\n      transitions: {\n        &#039;Failed&#039;: {\n          targetState: &#039;Failed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty()) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;&lt;a href=&quot;&#039; + resultSet.url + &#039;&quot;&gt; &#039; + resultSet.id + &#039;&lt;\/a&gt;&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n                \/\/ Updating Test Run Status \n                parent.fields[&quot;Status&quot;] = ctx.Status.Failing;\n              } else {\n                parent.fields[&quot;Status&quot;] = ctx.Status.Failed;\n              }\n            }\n          }\n        },\n        &#039;Passed&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;Passed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty()) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;&lt;a href=&quot;&#039; + resultSet.url + &#039;&quot;&gt; &#039; + resultSet.id + &#039;&lt;\/a&gt;&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n                parent.fields[&quot;Status&quot;] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else {\n                parent.fields[&quot;Status&quot;] = (isPassing) ? ctx.Status.Passed : ctx.Status.Failed;\n              }\n            }\n          }\n        }\n      }\n    },\n    Passed: {\n      transitions: {\n        &#039;Failed&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;Failed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty()) {\n             var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;&lt;a href=&quot;&#039; + resultSet.url + &#039;&quot;&gt; &#039; + resultSet.id + &#039;&lt;\/a&gt;&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n                parent.fields[&quot;Status&quot;] = ctx.Status.Failing;\n              } else {\n                parent.Status = ctx.Status.Failed;\n              }\n            }\n          }\n        },\n        &#039;No Run&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;No Run&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty()) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var ActiveTestRun = false;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                  ActiveTestRun = true;\n                } else if ((v.Status.name == ctx.Status.Passed.name) &amp;&amp; (v.id !== issue.id)) {\n                  ActiveTestRun = true;\n                }\n              });\n              if (ActiveTestRun) {\n                parent.fields[&quot;Status&quot;] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else parent.fields[&quot;Status&quot;] = ctx.Status.InProgress;\n            }\n          }\n        }\n      }\n    },\n    Failed: {\n      transitions: {\n        &#039;Passed&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;Passed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty()) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if ((v.Status.name == ctx.Status.Failed.name) &amp;&amp; (v.id !== issue.id)) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;&lt;a href=&quot;&#039; + resultSet.url + &#039;&quot;&gt; &#039; + resultSet.id + &#039;&lt;\/a&gt;&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n\n                parent.fields[&quot;Status&quot;] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else {\n                parent.fields[&quot;Status&quot;] = (isPassing) ? ctx.Status.Passed : ctx.Status.Failed;\n              }\n            }\n          }\n        },\n        &#039;No Run&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;No Run&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty()) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var ActiveTestRun = false;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if ((v.Status.name == ctx.Status.Failed.name) &amp;&amp; (v.id !== issue.id)) {\n                  isPassing = false;\n                  ActiveTestRun = true;\n                } else if ((v.Status.name == ctx.Status.Passed.name) &amp;&amp; (v.id !== issue.id)) {\n                  ActiveTestRun = true;\n                }\n              });\n              if (ActiveTestRun) {\n                parent.fields[&quot;Status&quot;] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else parent.fields[&quot;Status&quot;] = ctx.Status.InProgress;\n            }\n          }\n        }\n      }\n    }\n  },\n  alternativeMachines: {\n    &#039;Test Run&#039;: {\n      &#039;No Run&#039;: {\n        initial: true,\n        transitions: {\n          &#039;Failing&#039;: {\n            targetState: &#039;Failing&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n         \/* Add actions. *\/\n            }\n          },\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n          \/* Add actions. *\/\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Failing: {\n        transitions: {\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n           \/* Add actions . *\/\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n          \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Passing: {\n        transitions: {\n          &#039;Failing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n              workflow.check(false, workflow.i18n(&#039;Test Run has-read-only status which is defined based on assigned tests statuses&#039;));\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Failed: {\n        transitions: {\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failing&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Passed: {\n        transitions: {\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n          \/* Add actions. *\/\n            },\n          },\n          &#039;Failing&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      }\n    }\n  },\n  requirements: {\n    Assignee: {\n      type: entities.User.fieldType\n    },\n    Status: {\n      type: entities.EnumField.fieldType,\n      InProgress: {\n        name: &#039;No Run&#039;\n      },\n      Failing: {\n        name: &#039;Failing&#039;\n      },\n      Passing: {\n        name: &#039;Passing&#039;\n      },\n      Passed: {\n        name: &#039;Passed&#039;\n      },\n      Failed: {\n        name: &#039;Failed&#039;\n      },\n    },\n    Type: {\n      type: entities.EnumField.fieldType,\n      TestRun: {\n        name: &quot;Test Run&quot;\n      },\n      TestExecution: {\n        name: &quot;Test Case Execution&quot;\n      }\n    },\n    Subtask: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Subtask&#039;,\n      inward: &#039;subtask of&#039;,\n      outward: &#039;parent for&#039;\n    },\n  }\n});\n <\/pre>\n<p>\n <\/details>\n<h1>Estat\u00edsticas de testes<\/h1>\n<p>Voc\u00ea tamb\u00e9m pode estar interessado nas principais estat\u00edsticas do ciclo de teste. Para efeitos desta demonstra\u00e7\u00e3o, incorporamos as seguintes m\u00e9tricas:<\/p>\n<ul>\n<li>N\u00famero total de testes atribu\u00eddos a uma passagem de teste espec\u00edfica.<\/li>\n<li>N\u00famero de testes com o status &#8220;Passed&#8221;.<\/li>\n<li>N\u00famero de testes com o status &#8220;Failed&#8221;.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done5s720.gif\" alt=\"\" \/><br \/>\nGra\u00e7as ao c\u00f3digo abaixo, todas as m\u00e9tricas s\u00e3o atualizadas no caso de qualquer uma das seguintes altera\u00e7\u00f5es: altera\u00e7\u00f5es de status do teste, a atribui\u00e7\u00e3o de um novo teste \u00e0 passagem de teste e a remo\u00e7\u00e3o de um teste da passagem de teste.<\/p>\n<details>\n<summary>\n        Expanda o bloco de c\u00f3digo<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n  exports.calculateStatuses = function(parent) {\n  var totalTR = 0;\n  var totalFailed = 0;\n  var totalPassed = 0;\n  if (!parent.links[&#039;parent for&#039;]) {\n    return;\n  } else {\n    parent.links[&#039;parent for&#039;].forEach(function(tr) {\n      totalTR++;\n      if (tr.Status.name == &#039;Passed&#039;) {\n        totalFailed++;\n      }\n      if (tr.Status.name == &#039;Failed&#039;) {\n        totalPassed++;\n      }\n    });\n    parent.fields[&#039;Total number of test cases&#039;] = totalTR;\n    parent.fields[&#039;Number of passed test cases&#039;] = totalPassed;\n    parent.fields[&#039;Number of failed test cases&#039;] = totalFailed;\n    return true;\n  }\n};\nexports.resetStatuses = function(testRun, testRunCopy) {\n   testRunCopy.fields[&#039;Total number of test cases&#039;] = testRun.fields[&#039;Total number of test cases&#039;];\n   testRunCopy.fields[&#039;Number of passed test cases&#039;] = 0;\n   testRunCopy.fields[&#039;Number of failed test cases&#039;] = 0;\n  return true;\n};\n<\/pre>\n<p>\n<\/details>\n<p>No nosso caso, esse c\u00f3digo \u00e9 acionado em v\u00e1rias regras de workflow, como &#8220;Update stats when links are adjusted&#8221; e &#8220;Switch to the next test case&#8221;, entre outras. Se quiser adotar um conjunto de m\u00e9tricas que se adaptem \u00e0s suas necessidades espec\u00edficas, voc\u00ea poder\u00e1 adicionar os campos personalizados necess\u00e1rios e ajustar sua l\u00f3gica de workflow.<\/p>\n<h2>Recursos do rastreador de issues<\/h2>\n<p>Talvez voc\u00ea queira criar uma tarefa separada que resolva um bug encontrado para um teste com falha e vincul\u00e1-la a um issue que identifica a execu\u00e7\u00e3o do caso de teste relacionada. Voc\u00ea pode vincular os testes que falharam aos bugs relacionados usando um tipo de link de problema personalizado ou usar um campo de texto personalizado contendo uma refer\u00eancia ao bug. Pode ser mais f\u00e1cil organizar um projeto do YouTrack separado para manter o controle dos bugs.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS7.png\" alt=\"\" \/><\/p>\n<h2>Poss\u00edveis melhorias<\/h2>\n<p>Voc\u00ea pode estender a funcionalidade do YouTrack para atender a requisitos comerciais adicionais. Aqui est\u00e3o v\u00e1rias op\u00e7\u00f5es a serem consideradas.<\/p>\n<h3>Clonagem de uma passagem de teste existente<\/h3>\n<p>\u00c0s vezes, pode ser muito \u00fatil fazer uma nova passagem de teste semelhante a uma existente, mas que inclua algumas pequenas altera\u00e7\u00f5es (por exemplo, uma mudan\u00e7a na vers\u00e3o atribu\u00edda). O item de menu &#8220;Create Test Run copy&#8221; \u00e9 criado precisamente para esses casos. Esse item de menu est\u00e1 dispon\u00edvel apenas para issues do tipo &#8220;Test Run&#8221; e aciona as seguintes a\u00e7\u00f5es:<\/p>\n<ul>\n<li>Cria uma c\u00f3pia da passagem de teste, bem como c\u00f3pias das execu\u00e7\u00f5es de caso de teste atribu\u00eddas a ela.<\/li>\n<li>All newly created test case execution copies are assigned to the new test run using the \u2018parent-child\u2019 issue link type. Al\u00e9m disso, essas c\u00f3pias ser\u00e3o atribu\u00eddas aos casos de teste originais com o tipo de link de issue &#8220;Execution&#8221; (para manter a rastreabilidade).<\/li>\n<li>All statuses and statistics will be discarded for the newly created issue. <\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done8s720.gif\" alt=\"\" \/><\/p>\n<p>A l\u00f3gica acima \u00e9 implementada usando a regra de a\u00e7\u00e3o &#8220;Create Test Run copy&#8221;.<\/p>\n<details>\n<summary>\n        Expanda o bloco de c\u00f3digo<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\nvar workflow = require(&#039;@jetbrains\/youtrack-scripting-api\/workflow&#039;);\nvar entities = require(&#039;@jetbrains\/youtrack-scripting-api\/entities&#039;);\nvar utils = require(&#039;..\/calculate-tms-stats\/utils&#039;);\n\nexports.rule = entities.Issue.action({\n  title: &#039;Create Test Run copy&#039;,\n  command: &#039;Test Run Creation&#039;,\n  guard: function(ctx) {\n    return ctx.issue.isReported &amp;&amp; (ctx.issue.Type.name == ctx.Type.TestRun.name);\n  },\n  action: function(ctx) {\n    var issue = ctx.issue;\n    var TestRunCopy = issue.copy(issue.project);\n    TestRunCopy.Status = ctx.Status.InProgress; \n    var oldTestList = issue.links[ctx.Subtask.outward];\n    oldTestList.forEach(function(v) {\n      var newTest = v.copy(v.project);\n      newTest.Status = ctx.Status.InProgress;\n      newTest.links[ctx.Subtask.inward].delete(issue);\n      newTest.links[ctx.Subtask.inward].add(TestRunCopy);\n    });\n    utils.resetStatuses(issue, TestRunCopy); \n    var newTestRunLink = &#039;&lt;a href=&quot;&#039; + TestRunCopy.url + &#039;&quot;&gt; &#039; + TestRunCopy.id + &#039;&lt;\/a&gt;&#039;;\n    var message = &#039;New Test Run has been created &#039; + newTestRunLink + &#039;.&#039;;\n    workflow.message(message);\n  },\n  requirements: {\n    Execution: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Execution&#039;,\n      inward: &#039;Execution&#039;,\n      outward: &#039;Assigned Test case or test suite&#039;\n    },\n    Subtask: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Subtask&#039;,\n      inward: &#039;subtask of&#039;,\n      outward: &#039;parent for&#039;\n    },\n    Type: {\n      type: entities.EnumField.fieldType,\n      TestRun: {\n        name: &quot;Test Run&quot;\n      },\n    },\n    Status: {\n      type: entities.EnumField.fieldType,\n      InProgress: {\n        name: &#039;No Run&#039;\n      },\n    }\n  }\n});\n <\/pre>\n<p>\n <\/details>\n<h2>Restringir as a\u00e7\u00f5es do usu\u00e1rio<\/h2>\n<p>Para evitar poss\u00edveis erros ao trabalhar com cen\u00e1rios de teste (por exemplo, usando os tipos de issues incorretos), voc\u00ea pode restringir as poss\u00edveis a\u00e7\u00f5es dos usu\u00e1rios. Por exemplo, voc\u00ea pode implementar a\u00e7\u00f5es para garantir que os usu\u00e1rios vinculem casos de teste a passagens de testes. When the user links a test run to an issue, this action will check whether the linked issue type is \u2018Test Case\u2019 or \u2018Test Suite.\u2019 Se n\u00e3o for nenhum dos dois, a a\u00e7\u00e3o enviar\u00e1 um aviso que impedir\u00e1 o usu\u00e1rio de prosseguir.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done9.720.gif\" alt=\"\" \/><\/p>\n<p>O seguinte bloco de c\u00f3digo pode ser adicionado ao workflow &#8220;Populate Test Run&#8221;.<\/p>\n<details>\n<summary>\n        Expanda o bloco de c\u00f3digo<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n var message = &#039;&lt;a href=&quot;&#039; + TestCase.url + &#039;&quot;&gt; &#039; + TestCase.id + &#039;&lt;\/a&gt;&#039;;\n      workflow.check((TestCase.Type.name == ctx.Type.TestCase.name) || (TestCase.Type.name == ctx.Type.TestSuite.name), workflow.i18n(&#039;\\&#039;Test Run\\&#039; can be linked to \\&#039;Test Case\\&#039; and \\&#039;Test Suite\\&#039; only, but {0} has \\&#039;{1}\\&#039; type!&#039;, message, TestCase.Type.name));\n    <\/pre>\n<p>\n    <\/details>\n<p>Conforme mencionado <a href=\"#ref2\">acima<\/a>, o status da passagem de teste deve ser somente leitura, pois depende do andamento das execu\u00e7\u00f5es dos testes. Isso pode ser feito de maneira direta, simplesmente incluindo um bloco de c\u00f3digo que restrinja as mudan\u00e7as manuais de status para issues com o tipo de problema &#8220;Test Run&#8221;.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/done10s720.gif\" alt=\"\" \/><br \/>\nPor exemplo, a se\u00e7\u00e3o &#8216;transi\u00e7\u00f5es&#8217; para o tipo de issue &#8216;Test Run&#8217; no workflow &#8220;status-management&#8221; pode ser ajustado da seguinte maneira:<\/p>\n<details>\n<summary>\n        Expanda o bloco de c\u00f3digo<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n   &#039;Failing&#039;: {\n            targetState: &#039;Failing&#039;,\n            action: function(ctx) {\n              workflow.check(false, workflow.i18n(&#039;Test run has read-only status which is defined based on assigned tests statuses&#039;));\n            }\n          },\n          ...\n        }\n<\/pre>\n<p>\n<\/details>\n<h2>Relat\u00f3rios e rastreabilidade<\/h2>\n<h3>Relat\u00f3rios<\/h3>\n<p>Ao final do dia, ap\u00f3s o t\u00e9rmino do ciclo de teste, talvez voc\u00ea queira analisar os resultados. O recurso de relat\u00f3rios do YouTrack pode ser usado para essa finalidade. You can select the report type, which will display key information related to the test management procedure. Para efeitos dessa demonstra\u00e7\u00e3o, adicionaremos 2 relat\u00f3rios ao dashboard:<\/p>\n<ul>\n<li>\n<em><b>Relat\u00f3rio de fluxo cumulativo com filtragem pelo campo &#8220;version&#8221;.<\/b><\/em> Esse tipo de relat\u00f3rio de status se refere a uma vers\u00e3o espec\u00edfica do produto. Ele mostra as principais m\u00e9tricas, como o n\u00famero de testes com os status &#8220;Passed&#8221;, &#8220;Failed&#8221; e &#8220;No Run&#8221;, mapeados em uma linha do tempo. Para exibir dados de vers\u00e3o cruzada, voc\u00ea deve criar um relat\u00f3rio para cada vers\u00e3o. Pode ser conveniente adicionar todos os relat\u00f3rios ao painel para que voc\u00ea possa trabalhar com todos os dados em um s\u00f3 lugar.<\/p>\n<h3>Configura\u00e7\u00e3o do relat\u00f3rio:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS11.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS11.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a><\/p>\n<h3>Resultados do relat\u00f3rio:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS12.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS12.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a><\/p>\n<\/li>\n<li><em> <b>Relat\u00f3rio de distribui\u00e7\u00e3o de issues.<\/b><\/em> Esse relat\u00f3rio \u00e9 um snapshot que inclui as principais m\u00e9tricas (como o n\u00famero de passagens de testes com cada status) para v\u00e1rias vers\u00f5es do produto. Especificamente para essa demonstra\u00e7\u00e3o, inclu\u00edmos resultados de relat\u00f3rios que podem ajud\u00e1-lo a comparar vers\u00f5es e analisar a estabilidade da vers\u00e3o.<br \/>\n<h3>Configura\u00e7\u00e3o do relat\u00f3rio:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS13.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS13.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a><\/p>\n<h3>Resultados do relat\u00f3rio:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/re_res_cut.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/re_res_cut.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a>\n <\/li>\n<\/ul>\n<h2>Rastreabilidade <\/h2>\n<p>Como o YouTrack armazena as principais informa\u00e7\u00f5es relacionadas ao ciclo de teste para cada problema com o tipo &#8220;Test Execution&#8221;, voc\u00ea sempre pode acessar o hist\u00f3rico de teste e identificar bugs relacionados.<br \/>\nSe voc\u00ea tiver um caso de teste, poder\u00e1 consultar qualquer execu\u00e7\u00e3o de teste na qual ele esteja envolvido.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS15.png\" alt=\"\" \/><\/p>\n<p>Com a execu\u00e7\u00e3o de caso de teste, voc\u00ea pode consultar uma passagem de teste.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS16.png\" alt=\"\" \/><\/p>\n<p>Com uma execu\u00e7\u00e3o de caso de teste reprovada, voc\u00ea sempre pode consultar a lista de bugs associados.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS17.png\" alt=\"\" \/><\/p>\n<p>Para encontrar mais detalhes sobre os workflows descritos neste artigo ou para discutir outros t\u00f3picos relacionados ao fluxo de trabalho, sinta-se \u00e0 vontade para participar da nossa <a href=\"http:\/\/youtrack-community.herokuapp.com\/\" target=\"_blank\" rel=\"noopener\">Comunidade de workflows do YouTrack<\/a> no Slack.<\/p>\n","protected":false},"author":1086,"featured_media":83088,"comment_status":"closed","ping_status":"closed","template":"","categories":[1582,808],"tags":[1506,1510,6384,91,1545],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/youtrack\/98669"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/youtrack"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/types\/youtrack"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/users\/1086"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/comments?post=98669"}],"version-history":[{"count":1,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/youtrack\/98669\/revisions"}],"predecessor-version":[{"id":98670,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/youtrack\/98669\/revisions\/98670"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/media\/83088"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/media?parent=98669"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/categories?post=98669"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/tags?post=98669"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/cross-post-tag?post=98669"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}