Gitlab CI/CD: TypeScript/Cypress/Cucumber

  1. Generiere ein neues Projekt in deinem Arbeitsbereich

  2. Stellen Sie sicher, dass Node.js installiert ist.

  3. Installieren Sie Cypress mit TypeScript: „npm install --save-dev typescript“ es wird die folgende Struktur ergeben:

Kopieren Sie die folgenden Abhängigkeiten in Ihre package.json:

"dependencies": {
 "@badeball/cypress-cucumber-preprocessor": "latest",
 "@cypress/webpack-preprocessor": "latest",
 "cypress": "latest",
 "ts-loader": "latest",
 "typescript": "latest"
}

Führen npm install aus, um die neuesten Versionen der Abhängigkeiten zu installieren.

Schreiben Sie einen Testfall mit Gherkin-Syntax und erstellen Sie eine zusätzliche Datei mit Steps Definition. Legen Sie beide Dateien im Projektordner /Cypress/e2e/ ab:

Zur Automatisierungszwecken nehmen wir an, dass der .feature-Name auf der tatsächlichen Aqua-Testfall-Id basiert: z.B. im obigen Fall haben wir den Aqua-Testfall mit Id=270 aktualisiert.

Unsere einfache 270.feature Datei sieht folgendermaßen aus:

Feature: Test Case 270
 Scenario: visiting the frontpage
   Given I am on web page "https://example.cypress.io"
   When I click on type
   Then URL should include "/commands/actions"


   When I click on type
   Then URL should include "/commands/type"

Schritte Definition 270.ts-Datei sieht wie folgt aus:

import { Given, When, Then } from "@badeball/cypress-cucumber-preprocessor";


Given("I am on web page {string}", (webpage) => {
 cy.visit(`${webpage}`)
});


When("I click on type", ()=>{
 cy.contains('type').click()
})


When("I type {string} to locator {string}", (msg,locator)=>{
 cy.get(`${locator}`).type(`${msg}`)
})


Then("URL should include {string}", (pattern)=>{
 cy.url().should('include', `${pattern}`);
});

Navigiere zu deiner cypress.config.ts-Datei und füge den folgenden Inhalt ein:

import { defineConfig } from "cypress";
import * as webpack from "@cypress/webpack-preprocessor";
import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor";


async function setupNodeEvents(
 on: Cypress.PluginEvents,
 config: Cypress.PluginConfigOptions
): Promise<Cypress.PluginConfigOptions> {
 // This is required for the preprocessor to be able to generate JSON reports after each run, and more,
 await addCucumberPreprocessorPlugin(on, config);


 on(
   "file:preprocessor",
   webpack({
     webpackOptions: {
       resolve: {
         extensions: [".ts", ".js"],
       },
       module: {
         rules: [
           {
             test: /\.ts$/,
             exclude: [/node_modules/],
             use: [
               {
                 loader: "ts-loader",
               },
             ],
           },
           {
             test: /\.feature$/,
             use: [
               {
                 loader: "@badeball/cypress-cucumber-preprocessor/webpack",
                 options: config,
               },
             ],
           },
         ],
       },
     },
   })
 );


 // Make sure to return the config object as it might have been modified by the plugin.
 return config;
}


export default defineConfig({
 e2e: {
   baseUrl: "https://duckduckgo.com",
   specPattern: "**/*.feature",
   chromeWebSecurity: false,
   setupNodeEvents,
 },
});


Jetzt müssen wir die aqua-Testfallausführung basierend auf dem Ergebnis des Cypress/Cucumber-Feature-Laufs aktualisieren. Um dies allgemein und ausführbar für alle Fälle zu machen, fügen wir einen „AfterEach”-Hook-Block in die Support-Datei …/cypress/support/e2e.ts hinzu.

import { EnvAquaRestConfig } from '../../aquaClient/envAquaRestConfig';
import { ApiTestExecutionNew, ApiTestStepExecutionStepType, ApiTestStepExecutionUpdateStatus, TestExecutionClient } from '../../aquaClient/src/api/aqua';
import './commands'
import fetch from "node-fetch";


// Alternatively you can use CommonJS syntax:
// require('./commands')


beforeEach (() => {


})


afterEach(async function () {


   const restConfig = new EnvAquaRestConfig();
   const client = new TestExecutionClient(restConfig.url, { fetch });
   const testCaseId = Number(Cypress.spec.fileName);


   cy.log(Cypress.spec.fileName);
   let stepStatus = ApiTestStepExecutionUpdateStatus.Pass;
   if (this.currentTest.state === 'failed') {
     stepStatus = ApiTestStepExecutionUpdateStatus.Failed;
   } else if (this.currentTest.state != 'passed') {
     throw new Error('no such status for test case execution');
   }
  
   const executionData = {
     Guid: undefined,
     TestCaseId: testCaseId,
     TestCaseName: undefined,
     Finalize: false,
     ValueSetName: undefined,
     TestScenarioInfo: undefined,
     Steps: [
       {
         Index: 1,
         Name: 'Step 1',
         StepType: ApiTestStepExecutionStepType.Step,
         Status: stepStatus,
       },
     ],
     TestedVersion: undefined,
     ExecutionDuration: undefined,
     AttachedLabels: undefined,
     CustomFields: undefined,
     Attachments: undefined
   } as unknown as ApiTestExecutionNew;
    await client.create([executionData]);
  
 })

Für die obige API-Anfrage müssen wir den Ausführungsstatus des Testfalls von Cypress kennen. Dies geschieht durch "cy.currentTest.state".

Um aqua mit Testfallausführungsinformationen zu aktualisieren, müssen wir auch die Aqua-Testfall-ID angeben: Im obigen Beispiel wird die Testfall-ID aus „Number(Cypress.spec.fileName)“ extrahiert.

Klassen, die wir für API-Aufrufe verwenden, können aus dem hier verfügbaren JSON-Schema generiert werden:

Nach erfolgreicher JUnit-Testausführung sollten wir die entsprechende einzelne Testfallausführung in aqua sehen.

Um das oben erwähnte Cypress/Cucumber-Projekt mit GitLab CI/CD ausführen zu können, müssen wir die entsprechende Workflow-Datei .gitlab-ci.yml erstellen. Ein einfaches Beispiel eines .gitlab-ci.yml-Skripts wird unten gezeigt:

stages:
 - test


test:
 image: cypress/browsers
 stage: test
 script:
   # install dependencies
   - npm ci
   # run Cypress tests
   - npx cypress run --browser chrome

Sobald ein GitLab-Test-Runner konfiguriert und mit Ihren GitLab-Projekten verbunden ist, können wir die GitLab-Pipeline mit dem obigen Workflow ausführen.

Last updated