diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index 6ead68d0..49fad2d5 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -36,3 +36,26 @@ jobs:
run: dotnet build .\SauceLabs.Visual\SauceLabs.Visual.csproj --no-restore
- name: Test
run: dotnet test --verbosity normal
+
+ integration-test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Build and push to local registry
+ uses: docker/build-push-action@v5
+ with:
+ context: '{{defaultContext}}:visual-dotnet'
+ tags: saucelabs/visual-dotnet
+ file: Dockerfile
+ load: true
+ - name: Run the integration tests
+ run: |
+ npm ci
+ npm run test
+ working-directory: tests
+ env:
+ SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
+ SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
+ CONTAINER_IMAGE_NAME: saucelabs/visual-dotnet
diff --git a/.github/workflows/java-build.yml b/.github/workflows/java-build.yml
index b1b86a5b..b1c1ca12 100644
--- a/.github/workflows/java-build.yml
+++ b/.github/workflows/java-build.yml
@@ -6,6 +6,7 @@ on:
- main
paths:
- 'visual-java/**'
+ - 'tests/**'
- .github/workflows/java-build.yml
pull_request:
paths:
@@ -36,3 +37,26 @@ jobs:
- name: Build and Lint with Maven
run: mvn -B verify --file pom.xml
if: matrix.version == '11'
+
+ integration-test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Build and push to local registry
+ uses: docker/build-push-action@v5
+ with:
+ context: '{{defaultContext}}:visual-java'
+ tags: saucelabs/visual-java
+ file: Dockerfile
+ load: true
+ - name: Run the integration tests
+ run: |
+ npm ci
+ npm run test
+ working-directory: tests
+ env:
+ SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
+ SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
+ CONTAINER_IMAGE_NAME: saucelabs/visual-java
diff --git a/.github/workflows/wdio-integration.yml b/.github/workflows/wdio-integration.yml
new file mode 100644
index 00000000..600777f6
--- /dev/null
+++ b/.github/workflows/wdio-integration.yml
@@ -0,0 +1,41 @@
+name: wdio (integration test)
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - 'visual-js/visual-wdio/**'
+ - .github/workflows/js-build.yml
+ pull_request:
+ paths:
+ - 'visual-js/visual-wdio/**'
+ - .github/workflows/js-build.yml
+
+defaults:
+ run:
+ working-directory: visual-js/visual-wdio
+
+jobs:
+ integration-test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Build and push to local registry
+ uses: docker/build-push-action@v5
+ with:
+ context: '{{defaultContext}}:visual-js/visual-wdio'
+ tags: saucelabs/visual-wdio
+ file: Dockerfile
+ load: true
+ - name: Run the integration tests
+ run: |
+ npm ci
+ npm run test
+ working-directory: tests
+ env:
+ SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
+ SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
+ CONTAINER_IMAGE_NAME: saucelabs/visual-wdio
diff --git a/tests/env-vars-custom-id.spec.ts b/tests/env-vars-custom-id.spec.ts
index cc1f991a..f59fea75 100644
--- a/tests/env-vars-custom-id.spec.ts
+++ b/tests/env-vars-custom-id.spec.ts
@@ -1,4 +1,4 @@
-import { BuildMode, BuildStatus, SauceRegion, getApi } from '@saucelabs/visual';
+import { BuildStatus, SauceRegion, getApi } from '@saucelabs/visual';
import {
RE_VISUAL_BUILD_ID,
RE_VISUAL_BUILD_LINK,
diff --git a/visual-dotnet/Dockerfile b/visual-dotnet/Dockerfile
new file mode 100644
index 00000000..f8653501
--- /dev/null
+++ b/visual-dotnet/Dockerfile
@@ -0,0 +1,11 @@
+FROM mcr.microsoft.com/dotnet/sdk:6.0
+
+WORKDIR /app
+COPY . .
+
+RUN dotnet restore
+
+ENV RUN_IT true
+
+# run tests on docker run
+ENTRYPOINT ["dotnet", "test", "--filter", "FullyQualifiedName~IntegrationTests"]
diff --git a/visual-dotnet/SauceLabs.Visual.IntegrationTests/IntegrationTestAttribute.cs b/visual-dotnet/SauceLabs.Visual.IntegrationTests/IntegrationTestAttribute.cs
new file mode 100644
index 00000000..5f3460e2
--- /dev/null
+++ b/visual-dotnet/SauceLabs.Visual.IntegrationTests/IntegrationTestAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+using NUnit.Framework;
+using NUnit.Framework.Interfaces;
+using NUnit.Framework.Internal;
+
+namespace SauceLabs.Visual.IntegrationTests;
+
+[AttributeUsage(AttributeTargets.Method, Inherited = false)]
+public class IntegrationTestAttribute : NUnitAttribute, IApplyToTest
+{
+ public void ApplyToTest(Test test)
+ {
+ if (test.RunState == RunState.NotRunnable)
+ {
+ return;
+ }
+
+ if (Environment.GetEnvironmentVariable("RUN_IT") != "true")
+ {
+ test.RunState = RunState.Ignored;
+ test.Properties.Set(PropertyNames.SkipReason, "This test runs only when RUN_IT is \"true\"");
+ }
+ }
+}
\ No newline at end of file
diff --git a/visual-dotnet/SauceLabs.Visual.IntegrationTests/LoginPage.cs b/visual-dotnet/SauceLabs.Visual.IntegrationTests/LoginPage.cs
new file mode 100644
index 00000000..5ea6b426
--- /dev/null
+++ b/visual-dotnet/SauceLabs.Visual.IntegrationTests/LoginPage.cs
@@ -0,0 +1,42 @@
+using System.Threading.Tasks;
+using NUnit.Framework;
+using OpenQA.Selenium.Remote;
+
+namespace SauceLabs.Visual.IntegrationTests;
+
+public class LoginPage
+{
+ private RemoteWebDriver? Driver { get; set; }
+ private VisualClient? VisualClient { get; set; }
+
+ [SetUp]
+ public async Task Setup()
+ {
+ var browserOptions = Utils.GetBrowserOptions();
+ var sauceOptions = Utils.GetSauceOptions();
+ browserOptions.AddAdditionalOption("sauce:options", sauceOptions);
+
+ var sauceUrl = Utils.GetOnDemandURL();
+ Driver = new RemoteWebDriver(sauceUrl, browserOptions);
+ Driver.ExecuteScript("sauce:job-name=NUnit C#/.Net Visual Session");
+
+ VisualClient = await VisualClient.Create(Driver, Region.UsWest1);
+ TestContext.Progress.WriteLine($"Build: {VisualClient.Build.Url}");
+ }
+
+ [IntegrationTest]
+ [Test]
+ public async Task LoginPage_ShouldOpen()
+ {
+ Driver.Navigate().GoToUrl("https://www.saucedemo.com");
+ await VisualClient.VisualCheck("Login Page");
+ }
+
+ [TearDown]
+ public async Task Teardown()
+ {
+ await VisualClient.Finish();
+ Driver?.Quit();
+ VisualClient?.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/visual-dotnet/SauceLabs.Visual.IntegrationTests/SauceLabs.Visual.IntegrationTests.csproj b/visual-dotnet/SauceLabs.Visual.IntegrationTests/SauceLabs.Visual.IntegrationTests.csproj
new file mode 100644
index 00000000..91b18f94
--- /dev/null
+++ b/visual-dotnet/SauceLabs.Visual.IntegrationTests/SauceLabs.Visual.IntegrationTests.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net6.0
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/visual-dotnet/SauceLabs.Visual.IntegrationTests/Utils.cs b/visual-dotnet/SauceLabs.Visual.IntegrationTests/Utils.cs
new file mode 100644
index 00000000..8ae90ec1
--- /dev/null
+++ b/visual-dotnet/SauceLabs.Visual.IntegrationTests/Utils.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using OpenQA.Selenium;
+using OpenQA.Selenium.Chrome;
+using OpenQA.Selenium.Firefox;
+using OpenQA.Selenium.Safari;
+
+namespace SauceLabs.Visual.IntegrationTests;
+
+internal static class Utils
+{
+ public static Dictionary GetSauceOptions()
+ {
+ return new Dictionary
+ {
+ { "username", GetSauceUsername() },
+ { "accessKey", GetSauceAccessKey() }
+ };
+ }
+
+ public static string GetSauceUsername()
+ {
+ var username = Environment.GetEnvironmentVariable("SAUCE_USERNAME");
+ if (string.IsNullOrEmpty(username))
+ {
+ throw new Exception("No SAUCE_USERNAME found");
+ }
+
+ return username;
+ }
+
+ public static string GetSauceAccessKey()
+ {
+ var accessKey = Environment.GetEnvironmentVariable("SAUCE_ACCESS_KEY");
+ if (string.IsNullOrEmpty(accessKey))
+ {
+ throw new Exception("No SAUCE_ACCESS_KEY found");
+ }
+
+ return accessKey;
+ }
+
+ public static string GetSauceRegion()
+ {
+ var region = Environment.GetEnvironmentVariable("SAUCE_REGION");
+ if (string.IsNullOrEmpty(region))
+ {
+ return "us-west-1";
+ }
+
+ return region;
+ }
+
+ public static Uri GetOnDemandURL()
+ {
+ var regionName = GetSauceRegion();
+ var tld = regionName == "staging" ? "net" : "com";
+ return new Uri("https://ondemand." + regionName + ".saucelabs." + tld + "/wd/hub");
+ }
+
+ public static DriverOptions GetBrowserOptions()
+ {
+ var browser = Environment.GetEnvironmentVariable("BROWSER_NAME");
+ DriverOptions browserOptions = browser switch
+ {
+ "Firefox" => new FirefoxOptions(),
+ "Safari" => new SafariOptions(),
+ _ => new ChromeOptions(),
+ };
+
+ browserOptions.PlatformName =
+ Environment.GetEnvironmentVariable("PLATFORM_NAME") ?? "Windows 11";
+ browserOptions.BrowserVersion =
+ Environment.GetEnvironmentVariable("BROWSER_VERSION") ?? "latest";
+ return browserOptions;
+ }
+}
\ No newline at end of file
diff --git a/visual-dotnet/SauceLabs.Visual.sln b/visual-dotnet/SauceLabs.Visual.sln
index 18a30766..b53728f3 100644
--- a/visual-dotnet/SauceLabs.Visual.sln
+++ b/visual-dotnet/SauceLabs.Visual.sln
@@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SauceLabs.Visual", "SauceLa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SauceLabs.Visual.Tests", "SauceLabs.Visual.Tests\SauceLabs.Visual.Tests.csproj", "{6D07FB36-1E01-4D6A-853F-E1548DBE234C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SauceLabs.Visual.IntegrationTests", "SauceLabs.Visual.IntegrationTests\SauceLabs.Visual.IntegrationTests.csproj", "{77A9E41F-CBB4-4E52-A3CE-8131E59B379D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
{6D07FB36-1E01-4D6A-853F-E1548DBE234C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D07FB36-1E01-4D6A-853F-E1548DBE234C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D07FB36-1E01-4D6A-853F-E1548DBE234C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {77A9E41F-CBB4-4E52-A3CE-8131E59B379D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {77A9E41F-CBB4-4E52-A3CE-8131E59B379D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {77A9E41F-CBB4-4E52-A3CE-8131E59B379D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {77A9E41F-CBB4-4E52-A3CE-8131E59B379D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/visual-java/Dockerfile b/visual-java/Dockerfile
new file mode 100644
index 00000000..aedd90bd
--- /dev/null
+++ b/visual-java/Dockerfile
@@ -0,0 +1,13 @@
+FROM eclipse-temurin:11-jdk-alpine AS runner
+
+RUN mkdir -p /workspace
+WORKDIR /workspace
+
+COPY ./.mvn /workspace/.mvn
+COPY ./src /workspace/src
+COPY ./pom.xml /workspace/
+COPY ./mvnw /workspace/
+
+RUN ./mvnw -q clean test-compile
+
+ENTRYPOINT ["./mvnw", "-q", "test" ,"-Dtest=com.saucelabs.visual.integration.**"]
diff --git a/visual-java/src/test/java/com/saucelabs/visual/integration/LoginPageIT.java b/visual-java/src/test/java/com/saucelabs/visual/integration/LoginPageIT.java
new file mode 100644
index 00000000..0fd362da
--- /dev/null
+++ b/visual-java/src/test/java/com/saucelabs/visual/integration/LoginPageIT.java
@@ -0,0 +1,36 @@
+package com.saucelabs.visual.integration;
+
+import com.saucelabs.saucebindings.SaucePlatform;
+import com.saucelabs.saucebindings.UnhandledPromptBehavior;
+import com.saucelabs.saucebindings.junit5.SauceBaseTest;
+import com.saucelabs.saucebindings.options.SauceOptions;
+import com.saucelabs.visual.DataCenter;
+import com.saucelabs.visual.VisualApi;
+import com.saucelabs.visual.junit5.TestMetaInfoExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith({TestMetaInfoExtension.class})
+class LoginPageIT extends SauceBaseTest {
+
+ public SauceOptions createSauceOptions() {
+ return SauceOptions.chrome()
+ .setPlatformName(SaucePlatform.WINDOWS_10)
+ .setUnhandledPromptBehavior(UnhandledPromptBehavior.IGNORE)
+ .setScreenResolution("1920x1080")
+ .build();
+ }
+
+ @Test
+ void checkLoginPage() {
+ VisualApi visual =
+ new VisualApi(
+ driver,
+ DataCenter.US_WEST_1,
+ System.getenv("SAUCE_USERNAME"),
+ System.getenv("SAUCE_ACCESS_KEY"));
+ driver.get("https://www.saucedemo.com");
+ visual.sauceVisualCheck("Login page");
+ System.out.println("Sauce Visual: " + visual.getBuild().getUrl());
+ }
+}
diff --git a/visual-js/visual-wdio/Dockerfile b/visual-js/visual-wdio/Dockerfile
new file mode 100644
index 00000000..abf58c1d
--- /dev/null
+++ b/visual-js/visual-wdio/Dockerfile
@@ -0,0 +1,13 @@
+FROM node:18 AS runner
+
+COPY ./integration-tests/configs ./configs
+COPY ./integration-tests/helpers ./helpers
+COPY ./integration-tests/pages ./pages
+COPY ./integration-tests/specs ./specs
+
+COPY ./integration-tests/package.json ./
+COPY ./integration-tests/tsconfig.json ./
+
+RUN npm install
+
+ENTRYPOINT ["npm", "run", "login-test"]
diff --git a/visual-js/visual-wdio/integration-tests/configs/e2e.constants.ts b/visual-js/visual-wdio/integration-tests/configs/e2e.constants.ts
new file mode 100644
index 00000000..3132bb19
--- /dev/null
+++ b/visual-js/visual-wdio/integration-tests/configs/e2e.constants.ts
@@ -0,0 +1,74 @@
+const USERNAME =
+ process.env.VISUAL_CHECK === 'true' ? 'visual_user' : 'standard_user';
+const PASSWORD = 'secret_sauce';
+export const DEFAULT_TIMEOUT = 30 * 1000;
+export const PAGES = {
+ CART: '/cart.html',
+ CHECKOUT_COMPLETE: '/checkout-complete.html',
+ CHECKOUT_PERSONAL_INFO: '/checkout-step-one.html',
+ CHECKOUT_SUMMARY: '/checkout-step-two.html',
+ LOGIN: '/',
+ SWAG_DETAILS: '/inventory-item.html',
+ SWAG_ITEMS: '/inventory.html',
+ SWAG_ITEMS_LONG: '/inventory-long.html',
+};
+export const PRODUCTS = {
+ BIKE_LIGHT: 0,
+ BOLT_SHIRT: 1,
+ ONE_SIE: 2,
+ TATT_SHIRT: 3,
+ BACKPACK: 4,
+ FLEECE_JACKET: 5,
+};
+export const LOGIN_USERS = {
+ LOCKED: {
+ username: 'locked_out_user',
+ password: PASSWORD,
+ },
+ NO_MATCH: {
+ username: 'd',
+ password: 'd',
+ },
+ NO_USER_DETAILS: {
+ username: '',
+ password: '',
+ },
+ NO_PASSWORD: {
+ username: USERNAME,
+ password: '',
+ },
+ PERFORMANCE: {
+ username: 'performance_glitch_user',
+ password: PASSWORD,
+ },
+ STANDARD: {
+ username: USERNAME,
+ password: PASSWORD,
+ },
+ VISUAL: {
+ username: 'visual_user',
+ password: PASSWORD,
+ },
+};
+export const PERSONAL_INFO = {
+ STANDARD: {
+ firstName: 'Sauce',
+ lastName: 'Bot',
+ zip: '94105',
+ },
+ NO_FIRSTNAME: {
+ firstName: '',
+ lastName: 'Bot',
+ zip: '94105',
+ },
+ NO_LAST_NAME: {
+ firstName: 'Sauce',
+ lastName: '',
+ zip: '94105',
+ },
+ NO_POSTAL_CODE: {
+ firstName: 'Sauce',
+ lastName: 'Bot',
+ zip: '',
+ },
+};
diff --git a/visual-js/visual-wdio/integration-tests/configs/wdio.saucelabs.desktop.conf.ts b/visual-js/visual-wdio/integration-tests/configs/wdio.saucelabs.desktop.conf.ts
new file mode 100644
index 00000000..ec8d621d
--- /dev/null
+++ b/visual-js/visual-wdio/integration-tests/configs/wdio.saucelabs.desktop.conf.ts
@@ -0,0 +1,30 @@
+import type { Options } from '@wdio/types';
+import { config as sauceSharedConfig } from './wdio.saucelabs.shared.conf.ts';
+
+const buildName = `Sauce Demo Test - ${new Date().getTime()}`;
+
+export const config: Options.Testrunner = {
+ ...sauceSharedConfig,
+ //
+ // ============
+ // Capabilities
+ // ============
+ capabilities: [
+ {
+ browserName: 'chrome',
+ browserVersion: 'latest',
+ platformName: 'Windows 11',
+ 'sauce:options': {
+ screenResolution: '2560x1600',
+ build: buildName,
+ },
+ },
+ ],
+ // =====
+ // Hooks
+ // =====
+ before: async (_capabilities, _specs) => {
+ // Set all browsers to the "same" viewport
+ await browser.setWindowRect(null, null, 1920, 1080);
+ },
+};
diff --git a/visual-js/visual-wdio/integration-tests/configs/wdio.saucelabs.shared.conf.ts b/visual-js/visual-wdio/integration-tests/configs/wdio.saucelabs.shared.conf.ts
new file mode 100644
index 00000000..272dc43e
--- /dev/null
+++ b/visual-js/visual-wdio/integration-tests/configs/wdio.saucelabs.shared.conf.ts
@@ -0,0 +1,46 @@
+import type { Options } from '@wdio/types';
+import { config as sharedConfig } from './wdio.shared.conf.ts';
+import { getSauceCredentials } from '../helpers/index.ts';
+
+//
+// Get the Sauce Labs credentials
+const { sauceUsername, sauceAccessKey } = await getSauceCredentials();
+
+export const config: Options.Testrunner = {
+ ...sharedConfig,
+ //
+ // =================
+ // Service Providers
+ // =================
+ user: sauceUsername,
+ key: sauceAccessKey,
+ region: (process.env.REGION || 'us') as Options.SauceRegions,
+ //
+ // ============
+ // Capabilities
+ // ============
+ // Are not configured here, they can be found in:
+ // - wdio.saucelabs.desktop.conf.ts
+ // - wdio.saucelabs.mobile.conf.ts
+ //
+ // ========
+ // Services
+ // ========
+ services: (sharedConfig.services || []).concat([
+ //
+ // This service is needed for WDIO to make sure it can connect to Sauce Labs to:
+ // - automatically update the names
+ // - automatically update the status (passed/failed)
+ // - automatically send the stacktrace in case of a failure
+ //
+ 'sauce',
+ //
+ // This service is needed for the Sauce Visual service to work
+ //
+ [
+ '@saucelabs/wdio-sauce-visual-service',
+ // The options for the Sauce Visual service
+ {},
+ ],
+ ]),
+};
diff --git a/visual-js/visual-wdio/integration-tests/configs/wdio.shared.conf.ts b/visual-js/visual-wdio/integration-tests/configs/wdio.shared.conf.ts
new file mode 100644
index 00000000..00f994d8
--- /dev/null
+++ b/visual-js/visual-wdio/integration-tests/configs/wdio.shared.conf.ts
@@ -0,0 +1,307 @@
+import { join } from 'path';
+import type { Options } from '@wdio/types';
+
+export const config: Options.Testrunner = {
+ //
+ // ====================
+ // Runner Configuration
+ // ====================
+ // WebdriverIO supports running e2e tests as well as unit and component tests.
+ runner: 'local',
+ autoCompileOpts: {
+ autoCompile: true,
+ tsNodeOpts: {
+ project: './tsconfig.json',
+ transpileOnly: true,
+ },
+ },
+ //
+ // =================
+ // Service Providers
+ // =================
+ // WebdriverIO supports Sauce Labs, Browserstack, Testing Bot and LambdaTest (other cloud providers
+ // should work too though). These services define specific user and key (or access key)
+ // values you need to put in here in order to connect to these services.
+ //
+ // =======================================================
+ // See wdio.saucelabs.shared.conf.ts for more information.
+ // =======================================================
+ //
+ // ==================
+ // Specify Test Files
+ // ==================
+ // Define which test specs should run. The pattern is relative to the directory
+ // of the configuration file being run.
+ //
+ // The specs are defined as an array of spec files (optionally using wildcards
+ // that will be expanded). The test for each spec file will be run in a separate
+ // worker process. In order to have a group of spec files run in the same worker
+ // process simply enclose them in an array within the specs array.
+ //
+ // If you are calling `wdio` from an NPM script (see https://docs.npmjs.com/cli/run-script),
+ // then the current working directory is where your `package.json` resides, so `wdio`
+ // will be called from there.
+ //
+ specs: [join(process.cwd(), './tests/specs/*.spec.ts')],
+ // Patterns to exclude.
+ exclude: [
+ // 'path/to/excluded/files'
+ ],
+ //
+ // ============
+ // Capabilities
+ // ============
+ // Define your capabilities here. WebdriverIO can run multiple capabilities at the same
+ // time. Depending on the number of capabilities, WebdriverIO launches several test
+ // sessions. Within your capabilities you can overwrite the spec and exclude options in
+ // order to group specific specs to a specific capability.
+ //
+ // First, you can define how many instances should be started at the same time. Let's
+ // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
+ // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
+ // files and you set maxInstances to 10, all spec files will get tested at the same time
+ // and 30 processes will get spawned. The property handles how many capabilities
+ // from the same test should run tests.
+ //
+ maxInstances: 10,
+ //
+ // If you have trouble getting all important capabilities together, check out the
+ // Sauce Labs platform configurator - a great tool to configure your capabilities:
+ // https://saucelabs.com/platform/platform-configurator
+ //
+ // =================================
+ // For capabilities see:
+ // - wdio.saucelabs.desktop.conf.ts
+ // =================================
+ //
+ capabilities: [],
+ //
+ // ===================
+ // Test Configurations
+ // ===================
+ // Define all options that are relevant for the WebdriverIO instance here
+ //
+ // Level of logging verbosity: trace | debug | info | warn | error | silent
+ logLevel: 'info',
+ //
+ // Set specific log levels per logger
+ // loggers:
+ // - webdriver, webdriverio
+ // - @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
+ // - @wdio/mocha-framework, @wdio/jasmine-framework
+ // - @wdio/local-runner
+ // - @wdio/sumologic-reporter
+ // - @wdio/cli, @wdio/config, @wdio/utils
+ // Level of logging verbosity: trace | debug | info | warn | error | silent
+ // logLevels: {
+ // webdriver: 'info',
+ // '@wdio/appium-service': 'info'
+ // },
+ //
+ // If you only want to run your tests until a specific amount of tests have failed use
+ // bail (default is 0 - don't bail, run all tests).
+ bail: 0,
+ //
+ // Set a base URL in order to shorten url command calls. If your `url` parameter starts
+ // with `/`, the base url gets prepended, not including the path portion of your baseUrl.
+ // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
+ // gets prepended directly.
+ baseUrl: 'https://saucedemo.com',
+ //
+ // Default timeout for all waitFor* commands.
+ waitforTimeout: 10000,
+ //
+ // Default timeout in milliseconds for request
+ // if browser driver or grid doesn't send response
+ connectionRetryTimeout: 120000,
+ //
+ // Default request retries count
+ connectionRetryCount: 3,
+ //
+ // Test runner services
+ // Services take over a specific job you don't want to take care of. They enhance
+ // your test setup with almost no effort. Unlike plugins, they don't add new
+ // commands. Instead, they hook themselves up into the test process.
+ //
+ // ==============================================================
+ // For implementing Sauce Labs, see wdio.saucelabs.shared.conf.ts
+ // ==============================================================
+ //
+ services: [],
+
+ // Framework you want to run your specs with.
+ // The following are supported: Mocha, Jasmine, and Cucumber
+ // see also: https://webdriver.io/docs/frameworks
+ //
+ // Make sure you have the wdio adapter package for the specific framework installed
+ // before running any tests.
+ framework: 'mocha',
+ //
+ // The number of times to retry the entire specfile when it fails as a whole
+ // specFileRetries: 1,
+ //
+ // Delay in seconds between the spec file retry attempts
+ // specFileRetriesDelay: 0,
+ //
+ // Whether or not retried spec files should be retried immediately or deferred to the end of the queue
+ // specFileRetriesDeferred: false,
+ //
+ // Test reporter for stdout.
+ // The only one supported by default is 'dot'
+ // see also: https://webdriver.io/docs/dot-reporter
+ reporters: ['spec'],
+
+ //
+ // Options to be passed to Mocha.
+ // See the full list at http://mochajs.org/
+ mochaOpts: {
+ ui: 'bdd',
+ timeout: 60000,
+ },
+ //
+ // =====
+ // Hooks
+ // =====
+ // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
+ // it and to build services around it. You can either apply a single function or an array of
+ // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
+ // resolved to continue.
+ /**
+ * Gets executed once before all workers get launched.
+ * @param {object} config wdio configuration object
+ * @param {Array.