Handshake
Handshake
Handshake
  • ๐ŸŠIntroduction
  • ๐ŸšŸSupported Frameworks
    • PyTest
    • WebdriverIO
  • ๐ŸซReference
    • ๐Ÿ“”Enhancements/Issuses
    • ๐Ÿ“–Storybook
  • Installation
  • ๐Ÿ‘ฃRelease Notes
    • ๐Ÿฉน0.7.9
  • ๐ŸšจPlease Note
    • ๐Ÿ—’๏ธReverting to the Older Version
  • ๐Ÿค—Why
  • ๐Ÿ’กIdea
  • ๐ŸŽHow Does
    • Entity Type
    • ๐ŸงชStatus Calculation
Powered by GitBook
On this page
  • Command line
  • Sample Config Files
  • API Reference
  • Know More
  1. Supported Frameworks

WebdriverIO

Setting up handshake reporter for WebdriverIO framework

PreviousPyTestNextInstallation

Last updated 10 months ago

We support reporting services for the WebdriverIO test framework. To get started,

  1. Download - npm install wdio-handshake-reporter

  2. Execute this command to confirm the successful installation npx shake --help

pnpm i wdio-handshake-reporter && pnpx shake --help

npm install wdio-handshake-reporter && npx shake --help

Command line

you will see the below message or similar for npx shake --help

npx shake -b TestResults TestReports

assumes you have saved your TestResults in the folder named "TestResults", then we export the TestResults to a folder called "TestReports".

  • Requires Venv Activation before using it

  • Replaces Existing TestReports if found

  • Generates static output

you can serve the static reports located at TestReports like with, : npx serve TestReports

Requires Venv Activation before using it

What it does:

  1. Gives the Version of the Custom Reporter

  2. Check whether you want to update your handshakes Python package

In case you want to fix the mismatch in the version, execute: npx shake -fix-version. but note it will not update your requirements.txt or any of your lock files for Python packages.

Sample Message

Shake CLI: A tool to use handshake CLI with a custom reporter context.

Note: To use most commands in Shake CLI, you need to first activate the virtual environment.

--version or -v: Checks if the version matches with the required version against the python-build. If not, it installs the required version.
--build or -b: Requires two arguments - TestResults followed by TestReports. TestResults is where your results are stored, and TestReports is where the generated reports will be saved.
--download or -d: Downloads the raw build for the dashboard. This command is typically called automatically post-installation.
--help or -h: Prints this help message.
Examples:
npx shake --build Results Reports
npx shake -b Results Reports
npx shake -d
npx shake --download

Sample Config Files


import type { Options } from "@wdio/types";
import { attachReporter } from "wdio-handshake-reporter";

const options: Options.Testrunner = {
	runner: "local",
	autoCompileOpts: {
		autoCompile: true,
		tsNodeOpts: {
			project: "./tsconfig.json",
			transpileOnly: true,
		},
	},
	specs: ["./features/**/*.feature"],
	logLevel: "info",
	framework: "cucumber",
	reporters: ["spec"],
	cucumberOpts: {
		require: ["./features/step-definitions/steps.ts"],
	},

};

export const config = attachReporter(options, {
	resultsFolderName: "TestResults",
	port: 6969,
	addScreenshots: true,
	testConfig: {
		projectName: "test-wdio-cucumber",
	},
});
import { join, dirname } from 'node:path';
import { attachReporter } from "wdio-handshake-reporter"

const metaConfig = {
    reporterSyncTimeout: 40e3, // IMPORTANT
    runner: 'local',
    specs: [
        './test-mocha/specs/test.e2e.js',
        './test-mocha/specs/package-version.e2e.js',
    ],
    maxInstances: 10,
    specFileRetries: 1,
    //
    capabilities: [{
        browserName: 'chrome',
        'goog:chromeOptions': {
            args: ['headless', 'disable-gpu']
        }
    }],
    logLevel: 'info',
    bail: 0,
    baseUrl: 'http://localhost',
    waitforTimeout: 10000,
    framework: 'mocha',
    mochaOpts: {
        ui: 'bdd',
        timeout: 60000,
        grep: "(version|login)"
    },
    beforeTest: async function () {
        await browser.takeScreenshot();
    },
    afterTest: async function () {
        await browser.takeScreenshot();
    }
}

export const config = attachReporter(metaConfig, {
    resultsFolderName: "TestResults",
    port: 6966,
    requestsTimeout: 360e3,
    addScreenshots: true,
    testConfig: { projectName: 'test-wdio-mocha' },
    logLevel: "error",
    exportOutDir: "TestReports"
});

API Reference

attachReporter(...)

We would expect the attachReporter function to handle the required configuration for your file. attachReporter will add the required service: HandshakeService and HandshakeReporter to the services and reporters in the webdriver.Config

attachReporter(YOUR_CONFIG, HANDSHAKE_SPECIFIC_CONFIG) -> Returns the modified webdriver.Config

Know More


Refer to the below files on how it is implemented:

๐ŸšŸ
https://www.npmjs.com/package/wdio-handshake-reporter
serve
https://github.com/RahulARanger/handshake/blob/master/handshake-nodejs-reporters/packages/wdio-handshake-reporter/src/types.ts
import { Level } from 'pino';

export interface ReporterOptions {
  port: number; // port at which we would run the handshake server
  addScreenshots?:boolean; // do we need to add screenshots to the report ?
  requestsTimeout?:number; // dependent on reportSyncTimeout in webdriverIOConfig.
  logLevel?:Level; // log level for pino logger that we use
  disabled?: boolean; // make it true to not add reporter and service
  // if disabled it is as if we haven't added handshake-reporter
}
export interface HandshakeServiceOptions {
  port: number;
  root: string; // Results are stored relative to this root
  // and handshake.json is assumed to be in this root.
  resultsFolderName: string; // Results are stored in ${{ROOT}}/${{resultsFolderName}}
  requestsTimeout?: number; // we send bulk requests to the server so if it takes more than this,
  //  it will stop
  reportGenerationTimeout?:number; // stop generating reports if it takes more than this timeout
  workers?:number; // workers to support handshake-server
  logLevel?:Level; // log level for pino logger that we use (for custom service)
  exportOutDir?: string; // directory path to store the Dashboard (HTML) Reports
  testConfig: {
    projectName: string; // Name of the project
    avoidParentSuitesInCount?: boolean;
    // In Gherkin:
    // Feature -> Scenario -> Step.. in this case we get 2 suites but its 1.
    // so we ignore the parent suites in the totalNumberOfSuites.
    // do not use this unless required. it is true only when you cucumber as framework
    // else it is false.
  }
}

// for attachReporter function we need both (union) the above options
export type AttachReporterOptions = ReporterOptions & HandshakeServiceOptions & { root?: string };
https://github.com/RahulARanger/handshake/blob/master/handshake-nodejs-reporters/packages/wdio-handshake-reporter/src/helpers.ts
import type { Options } from '@wdio/types';
import { Assertion, checkVersion } from '@hand-shakes/common-handshakes';
import { AttachReporterOptions } from './types';
import HandshakeService from './service';
import HandshakeReporter from './reporter';
import { currentReporter } from './contacts';
import skipIfRequired from './internals';

/**
 * adds handshake custom reporter and service. provide the WebdriverIO Configuration
 * and required options to get started.
 * @param config WebdriverIO configuration object
 * @param options options to configure custom reporter and custom service
 * @returns modified WebdriverIO Configuration
 */
export function attachReporter(
  config: Options.Testrunner,
  options: AttachReporterOptions,
): Options.Testrunner {
  if (options.disabled) return config;
  checkVersion();

  const port = options.port ?? 6969;
  const toModify = config;

  toModify.reporters = toModify.reporters || [];
  toModify.services = toModify.services || [];

  toModify.reporters.push([
    HandshakeReporter,
    {
      port,
      addScreenshots: options.addScreenshots || false,
      requestsTimeout: Math.max(
        options.requestsTimeout ?? config.reporterSyncTimeout ?? 60e3,
        60e3,
      ),
      logLevel: options.logLevel ?? config.logLevel ?? 'info',
    },
  ]);

  toModify.services.push([
    HandshakeService,
    {
      port,
      requestsTimeout: Math.max(
        options.requestsTimeout
                    ?? config.connectionRetryTimeout
                    ?? 120e3,
        120e3,
      ),
      reportGenerationTimeout: Math.max(
        options.reportGenerationTimeout ?? 180e3,
        180e3,
      ),
      root: options.root,
      workers: options.workers,
      resultsFolderName: options.resultsFolderName,
      logLevel: options.logLevel ?? config.logLevel ?? 'info',
      testConfig: {
        ...options.testConfig,
        avoidParentSuitesInCount:
                    options.testConfig?.avoidParentSuitesInCount
                    ?? config.framework === 'cucumber',
      },
      exportOutDir: options.exportOutDir,
    },
  ]);

  return toModify;
}

/**
 * attaches custom screenshot to a current test case.
 * @param title title of the screenshot
 * @param content PNG content
 * @param description description for the screenshot
 * @param is_suite is it for suite ? so we take parent of the current test entity
 * @returns
 */
export async function attachScreenshot(
  title: string,
  content: string,
  description?: string,
  is_suite?: boolean,
) {
  if (skipIfRequired()) {
    return;
  }

  await currentReporter?.supporter?.attachScreenshot(
    title,
    content,
    currentReporter?.currentEntity(is_suite),
    description,
  );
}

/**
 * adds a description or the paragraph about the test or suite
 * @param content content to include in the description
 * @param is_suite is it for suite ? so we take parent of the current test entity
 * @returns
 */
export async function addDescription(content: string, is_suite?: boolean) {
  if (skipIfRequired()) {
    return;
  }

  await currentReporter?.supporter?.addDescription(
    content,
    currentReporter?.currentEntity(is_suite),
  );
}

/**
 * adds a link for reference for test or suite
 * @param url as it says
 * @param title title of the link
 * @param is_suite is it for suite ? so we take parent of the current test entity
 * @returns
 */
export async function addLink(url: string, title: string, is_suite?: boolean) {
  if (skipIfRequired()) {
    return;
  }

  await currentReporter?.supporter?.addLink(
    url,
    title,
    currentReporter?.currentEntity(is_suite),
  );
}

/**
 * adds the assertion for the current running test case
 * @param title title of the assertion
 * @param assertion assertion details
 * @returns
 */
export async function addAssertion(title: string, assertion: Assertion) {
  if (skipIfRequired()) {
    return;
  }

  await currentReporter?.supporter?.addAssertion(
    title,
    assertion,
    currentReporter?.currentTestID ?? '',
  );
}