Giter Site home page Giter Site logo

saucelabs / node-saucelabs Goto Github PK

View Code? Open in Web Editor NEW
92.0 17.0 45.0 2.95 MB

A wrapper around Sauce Labs API

License: Apache License 2.0

JavaScript 97.97% TypeScript 0.89% Mustache 1.07% Shell 0.07%
saucelabs api api-client rest sauce-labs sauce-connect hacktoberfest

node-saucelabs's Introduction

Node Sauce Labs Test Changes

Wrapper around all Sauce Labs REST APIs for Node.js (v14 or higher) including support for Sauce Connect Proxy and TypeScript definitions.

Install

To install the package run:

npm install saucelabs

Options

user

Your Sauce Labs username.

Type: string Default: process.env.SAUCE_USERNAME

key

Your Sauce Labs access key.

Type: string Default: process.env.SAUCE_ACCESS_KEY

region

Your Sauce Labs datacenter region. The following regions are available:

  • us-west-1 (short us)
  • eu-central-1 (short eu)

Type: string Default: us

proxy

If you want to tunnel your API request through a proxy please provide your proxy URL.

Type: string Default: null

headers

If you want to set request headers, as example {'User-Agent': 'node-saucelabs'}

Type: object
Default: {'User-Agent': 'saucelabs/<VERSION> (nodejs <PLATFORM>)'}

Usage

All accessible API commands with descriptions can be found here.

As CLI Tool

This package if installed globally can be used as CLI tool to access the API from the command line:

$ npm install -g saucelabs
...
$ sl listJobs $SAUCE_USERNAME --limit 5 --region eu
{ jobs:
   [ { id: '19dab74f8fd848518f8d2c2cee3a6fbd' },
     { id: 'dc08ca0c7fa14eee909a093d11567328' },
     { id: '5bc6f70c777b4ae3bf7909a40f5ee41b' },
     { id: 'f40fe7b044754eaaa5f5a130406549b5' },
     { id: 'd1553f71f910402893f1e82a4dcb6ca6' } ] }

You can find all available commands and options with description by calling:

$ sl --help
# show description for specific command
$ sl listJobs --help

or update the job status by calling:

$ sl updateJob cb-onboarding 690c5877710c422d8be4c622b40c747f "{\"passed\":false}"

or download a job asset:

$ sl downloadJobAsset 690c5877710c422d8be4c622b40c747f video.mp4 --filepath ./video.mp4

or upload a job asset:

$ sl uploadJobAssets 690c5877710c422d8be4c622b40c747f --files ./video.mp4 --files ./log.json

or start Sauce Connect Proxy in EU datacenter:

# start Sauce Connect tunnel for eu-central-1 region
$ sl sc --region eu --tunnel-name "my-tunnel"
# run a specific Sauce Connect version
$ sl sc --scVersion 4.5.4
# see all available Sauce Connect parameters via:
$ sl sc --help

You can see all available Sauce Connect parameters on the Sauce Labs Docs.

As NPM Package

The following example shows how to access details of the last job you were running with your account that is being exposed as environment variables as SAUCE_USERNAME and SAUCE_ACCESS_KEY. Alternatively you can pass the credentials via options to the constructor:

import SauceLabs from 'saucelabs';
// if imports are not supported by your Node.js version, import the package as follows:
// const SauceLabs = require('saucelabs').default;

(async () => {
  const myAccount = new SauceLabs();
  // using constructor options
  // const myAccount = new SauceLabs({ user: "YOUR-USER", key: "YOUR-ACCESS-KEY"});

  // get full webdriver url from the client depending on region:
  console.log(myAccount.webdriverEndpoint); // outputs "https://ondemand.us-west-1.saucelabs.com/"

  // get job details of last run job
  const jobs = await myAccount.listJobs(process.env.SAUCE_USERNAME, {
    limit: 1,
    full: true,
  });

  console.log(jobs);
  /**
     * outputs:
     * { jobs:
        [ { browser_short_version: '72',
            video_url:
             'https://assets.saucelabs.com/jobs/dc08ca0c7fa14eee909a093d11567328/video.flv',
            creation_time: 1551711453,
            'custom-data': null,
            browser_version: '72.0.3626.81',
            owner: '<username-redacted>',
            id: 'dc08ca0c7fa14eee909a093d11567328',
            record_screenshots: true,
            record_video: true,
            build: null,
            passed: null,
            public: 'team',
            end_time: 1551711471,
            status: 'complete',
            log_url:
             'https://assets.saucelabs.com/jobs/dc08ca0c7fa14eee909a093d11567328/selenium-server.log',
            start_time: 1551711454,
            proxied: false,
            modification_time: 1551711471,
            tags: [],
            name: null,
            commands_not_successful: 1,
            consolidated_status: 'complete',
            manual: false,
            assigned_tunnel_id: null,
            error: null,
            os: 'Windows 2008',
            breakpointed: null,
            browser: 'googlechrome' } ] }
     */

  /**
   * start Sauce Connect Proxy
   */
  const sc = await myAccount.startSauceConnect({
    /**
     * you can pass in a `logger` method to print Sauce Connect log messages
     */
    logger: (stdout) => console.log(stdout),
    /**
     * see all available parameters here: https://docs.saucelabs.com/dev/cli/sauce-connect-proxy/
     * all parameters have to be applied camel cased instead of with hyphens, e.g.
     * to apply the `--tunnel-name` parameter, set:
     */
    tunnelName: 'my-tunnel',
  });

  // run a test
  // ...

  // close Sauce Connect
  await sc.close();

  // upload additional log files and attach it to your Sauce job
  await myAccount.uploadJobAssets('76e693dbe6ff4910abb0bc3d752a971e', [
    // either pass in file names
    './logs/video.mp4',
    './logs/log.json',
    // or file objects
    {
      filename: 'myCustomLogFile.json',
      data: {
        someLog: 'data',
      },
    },
  ]);
})();

You may wonder why listJobs requires a username as first parameter since you've already defined the process.env. The reason for this is that Sauce Labs supports a concept of Team Accounts, so-called sub-accounts, grouped together. As such functions like the mentioned could list jobs not only for the requesting account, but also for the individual team account. Learn more about it here

webdriverEndpoint property

You can use the webdriverEndpoint property of the client to get the full WebDriver endpoint to connect to Sauce Labs, e.g.:

const myAccount = new SauceLabs({
  user: 'YOUR-USER',
  key: 'YOUR-ACCESS-KEY',
  region: 'eu', // run in EU datacenter
});

// get full webdriver url from the client depending on `region` option:
console.log(myAccount.webdriverEndpoint);
// outputs: "https://ondemand.eu-central-1.saucelabs.com/"

Contributors

This module was originally created by Dan Jenkins with the help of multiple contributors (Daniel Perez Alvarez, Mathieu Sabourin, Michael J Feher, and many more). We would like to thank Dan and all contributors for their support and this beautiful module.

License

Copyright 2012 Sauce Labs, Inc. Licensed Apache-2.0

node-saucelabs's People

Contributors

alexh-sauce avatar alexplischke avatar amilajack avatar aomarks avatar boneskull avatar christian-bromann avatar danjenkins avatar dependabot[bot] avatar diemol avatar enriquegh avatar ericmacfa avatar ericmacfarland avatar farhan-sauce avatar friggahel avatar martinfrancois avatar onioni avatar oss-sauce-bot avatar pauly avatar phearzero avatar qiyigg avatar shaunspringer avatar simonua avatar theandrewlane avatar tianfeng92 avatar unindented avatar waggledans avatar wswebcreation avatar youchenlee avatar zewa666 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-saucelabs's Issues

TypeScript check fails for region

Error:

src/reporter/reporter.ts:45:7 - error TS2322: Type 'string' is not assignable to type '"eu" | "us" | "us-west-1" | "eu-central-1"'.
45       region: browserData.region,
         ~~~~~~
  node_modules/saucelabs/build/index.d.ts:4:3
    4   region?: "us" | "eu" | "us-west-1" | "eu-central-1";
        ~~~~~~
    The expected type comes from property 'region' which is declared here on type 'SauceLabsOptions'

It should be possible to assign a string to it.

TypeError: Expected the `options.agent` properties to be `http`, `https` or `http2`, got `options`

Upgraded from v5 to v6 latest. With an internal proxy under corporate net in the config file seeing the below error.

2020-06-15T03:32:04.663Z ERROR @wdio/utils:initialiseServices: TypeError: Expected the options.agent properties to be http, https or http2, got options
at Function.normalizeArguments (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/got/dist/source/core/index.js:561:27)

To Reproduce

Expected behavior
No errors

Log
Execution of 1 spec files started at 2020-06-15T03:32:04.592Z

2020-06-15T03:32:04.663Z ERROR @wdio/utils:initialiseServices: TypeError:

Expected the `options.agent` properties to be `http`, `https` or `http2`, got `options`
    at Function.normalizeArguments (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/got/dist/source/core/index.js:561:27)
    at Function.normalizeArguments (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/got/dist/source/as-promise/core.js:34:31)
    at mergeOptions (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/got/dist/source/as-promise/core.js:108:47)
    at Function.got.extend.instancesOrOptions [as extend] (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/got/dist/source/create.js:127:22)
    at new SauceLabs (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/saucelabs/build/index.js:46:32)
    at new SauceLauncher (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/@wdio/sauce-service/build/launcher.js:28:16)
    at initialiseLauncherService (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/@wdio/utils/build/initialiseServices.js:61:31)
    at Launcher.run (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/@wdio/cli/build/launcher.js:73:48)
    at launch (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/@wdio/cli/build/commands/run.js:138:19)
    at handler (/Users/s0g04rg/Documents/SourceCode/star/_mine/wdio/node_modules/@wdio/cli/build/commands/run.js:171:12)

Additional context
As this error pops up, @wdio/saucelabs doesn't update the test name (sauce.context step/script)
(COMMAND executeScript("sauce:context=webdriver.io page - should have the right title", <object>))

Request : Support for non-callback usage

Hi guys,

I am liking this library a lot, it makes our tests a lot cleaner and streamlined. It would be great to have all saucelabs user use this as the standard library.

I am making a request since we are heavily taking advantage of the non-callback flow of mocha and paired with selenium-webdriver/testing lib.
http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_testing.html

This allows us to omit all callbacks in the mocha targets and makes the code even easier to develop.
But I am running into issues using a callback method inside a non-callback structure.
I am requesting to add support for methods without the callback (at least for the heavily used methods)
e.g. updateJob();

saucelabs.updateJob(sessionId, { name: currentTest.title, passed: passed });

So we can use it with this structure

var test = require('selenium-webdriver/testing');

test.describe('Suite', function() {
    this.timeout(2000);

    var driver;
    var sessionId;

    test.beforeEach(function() {
        driver = DriverBuilder.build();
        driver.getSession().then(function (sessionid){
            sessionId = sessionid.id_;
        });
    });

  test.afterEach(function() {
        var currentTest = this.currentTest;
        driver.quit();
        console.log('LOG : updating sauce');
        var passed = (currentTest.state === 'passed') ? true : false;
        var saucelabs = SauceLabsBuilder.build();
        saucelabs.updateJob(sessionId, { name: currentTest.title, passed: passed });
        console.log('Finished..');
    });
}

Currently only my test.afterEach() is an async variant so that I can pass done(); to saucelabs.updateJob()

    test.afterEach(function(done) {
        var currentTest = this.currentTest;
        driver.quit().then (function (){
            // update sauce labs job
            console.log('LOG : updating sauce');
            var passed = (currentTest.state === 'passed') ? true : false;
            var saucelabs = SauceLabsBuilder.build();
            saucelabs.updateJob(sessionId, { name: currentTest.title, passed: passed }, done);
            console.log('Finished..');
        });
    });

Thank you for all the great work with this library!

Release notes / CHANGELOG

Would it be possible to publish some release notes / CHANGELOG documentation for consumers to know what's changed between releases? At the very least, for major version bumps?

At present it's difficult to know what breaking change warranted the bump from v3 to v4, and I recall having similar issues with the API back when it went from v1 to v2 (see #61)

Add concurrency endpoint for xTM

Summary
As users move to xTM, they will need to use a different concurrency endpoint that is made to take teams into account.

This is /rest/v1.2/users/:username/concurrency

Currently, we only provide access to rest/v1.1/users/:username/concurrency via getUserConcurrency

AC

Add new endpoint to sauce.json Swagger to support this new endpoint.

Add storage API

Our live testing team has provided an OpenAPI spec for the recent released storage API. This should be added to our Node.js client. The spec is the following:

components:
  schemas:
    Access:
      properties:
        org_ids:
          description: list of organization ids that are allowed to access this entity
          items:
            type: string
          type: array
        team_ids:
          description: list of team ids that are allowed to access this entity
          items:
            type: string
          type: array
      type: object
    AndroidMetadata:
      properties:
        icon:
          description: base64-encoded PNG representation of the app icon
          nullable: true
          type: string
        identifier:
          description: unique package name
          example: com.mycompany.app
          type: string
        is_test_runner:
          description: true if the current package is a test runner
          nullable: true
          type: boolean
        min_sdk:
          description: minimum Android SDK version number this package supports
          example: 21
          format: int32
          nullable: true
          type: integer
        name:
          description: application name
          example: My Cool App
          type: string
        target_sdk:
          description: Android SDK version number this package was built for
          example: 28
          format: int32
          nullable: true
          type: integer
        version:
          description: value of versionName manifest value
          example: 1.2.3
          type: string
        version_code:
          description: value of versionCode manifest value
          example: 123
          format: int32
          type: integer
      type: object
    AndroidSettings:
      description: passing null to any setting tells the backend to reset it to its
        default value
      properties:
        instrumentation:
          allOf:
          - $ref: '#/components/schemas/Instrumentation'
          description: dictionary containing settings that depend on the app instrumentation
            state
          nullable: true
        instrumentation_enabled:
          default: true
          description: true if the app must be instrumented before running tests on
            it
          nullable: true
          type: boolean
        lang:
          default: en_GB
          description: language abbreviation to set for the app. See BCP-47 for more
            details
          type: string
        orientation:
          allOf:
          - $ref: '#/components/schemas/Orientation'
          default: null
          description: orientation value to set by default for the app
          nullable: true
        proxy:
          allOf:
          - $ref: '#/components/schemas/Proxy'
          description: proxy settings
          nullable: true
        proxy_enabled:
          default: false
          description: the given host and port will be applied to proxy network requests
            in automated tests if set to true
          nullable: true
          type: boolean
      type: object
    EditableFileProperties:
      properties:
        description:
          description: an optional custom description string of the file
          maxLength: 255
          nullable: true
          type: string
      type: object
    Error:
      properties:
        code:
          description: status code
          format: int32
          type: integer
        detail:
          description: details string
          type: string
        title:
          description: title string
          type: string
      type: object
    File:
      properties:
        access:
          allOf:
          - $ref: '#/components/schemas/Access'
          description: teams and orgs that have access to the file
          nullable: true
        description:
          description: an optional custom description string of the file
          type: string
        etag:
          description: hash sum of the uploaded binary calculated by the downstream
            storage
          type: string
        group_id:
          description: unique identifier of the group this file belongs to
          format: int64
          type: integer
        id:
          description: unique identifier of the file
          type: string
        kind:
          allOf:
          - $ref: '#/components/schemas/Kind'
          description: file platform name
        metadata:
          description: app metadata. Could be null for non-application groups
          nullable: true
          oneOf:
          - $ref: '#/components/schemas/IOSMetadata'
          - $ref: '#/components/schemas/AndroidMetadata'
        name:
          description: name of the file on the file system
          type: string
        owner:
          allOf:
          - $ref: '#/components/schemas/Owner'
          description: the info about the original file uploader
        upload_timestamp:
          description: file upload timestamp in UTC seconds since Unix Epoch
          format: int64
          type: integer
      type: object
    Group:
      properties:
        access:
          allOf:
          - $ref: '#/components/schemas/Access'
          description: teams and orgs that have access to the current group
        count:
          description: the count of files in the group
          format: int64
          type: integer
        id:
          description: unique identifier of the group
          format: int64
          type: integer
        name:
          description: the name of the group
          type: string
        recent:
          allOf:
          - $ref: '#/components/schemas/File'
          description: The most recently uploaded file info
          nullable: true
        settings:
          description: group settings. Could be null for non-application groups
          nullable: true
          oneOf:
          - $ref: '#/components/schemas/IOSSettings'
          - $ref: '#/components/schemas/AndroidSettings'
      type: object
    IOSMetadata:
      properties:
        icon:
          description: base64-encoded PNG representation of the app icon
          nullable: true
          type: string
        identifier:
          description: unique package name
          example: com.mycompany.app
          type: string
        is_simulator:
          description: true if the current package was built for Simulator
          type: boolean
        is_test_runner:
          description: true if the current package is a test runner
          nullable: true
          type: boolean
        min_os:
          description: minimum iOS version number this package supports
          example: '10'
          nullable: true
          type: string
        name:
          description: application name
          example: My Cool App
          type: string
        short_version:
          description: value of CFBundleShortVersionString manifest entry
          example: 1.2.3
          type: string
        target_os:
          description: IOS version number this package was built for
          example: '13'
          nullable: true
          type: string
        version:
          description: value of CFBundleVersion manifest entry
          example: '123'
          type: string
      type: object
    IOSSettings:
      description: passing null to any setting tells the backend to reset it to its
        default value
      properties:
        lang:
          default: en_GB
          description: language abbreviation to set for the app. See BCP-47 for more
            details
          type: string
        orientation:
          allOf:
          - $ref: '#/components/schemas/Orientation'
          default: null
          description: orientation value to set by default for the app
          nullable: true
        proxy:
          allOf:
          - $ref: '#/components/schemas/Proxy'
          description: proxy settings
          nullable: true
        proxy_enabled:
          default: false
          description: the given host and port will be applied to proxy network requests
            in automated tests if set to true
          nullable: true
          type: boolean
        resigning:
          allOf:
          - $ref: '#/components/schemas/Resigning'
          description: dictionary containing settings that depend on the app instrumentation
            state
          nullable: true
        resigning_enabled:
          default: true
          description: true if the app must be instrumented before running tests on
            it
          nullable: true
          type: boolean
      type: object
    Instrumentation:
      properties:
        bypass_screenshot_restriction:
          default: false
          description: whether to bypass Android restrictions while taking screenshots
            of views marked with FLAG_SECURE
          nullable: true
          type: boolean
        image_injection:
          default: true
          description: whether to enable image injection
          nullable: true
          type: boolean
      type: object
    Kind:
      enum:
      - ios
      - android
      - other
      type: string
    Links:
      properties:
        next:
          default: null
          description: relative link to the next page
          example: ?q=2&page=3%per_page=20
          nullable: true
          type: string
        prev:
          default: null
          description: relative link to the previous page
          example: ?q=2&page=1%per_page=20
          nullable: true
          type: string
        self:
          default: null
          description: relative link to the current page
          example: ?q=2&page=2%per_page=20
          nullable: true
          type: string
      type: object
    Orientation:
      enum:
      - LANDSCAPE
      - PORTRAIT
      type: string
    Owner:
      properties:
        id:
          description: unique identifier of the file uploader
          type: string
        org_id:
          description: unique identifier of the organization where the file uploader
            participates
          type: string
      type: object
    Proxy:
      properties:
        host:
          default: ''
          description: valid proxy host name
          type: string
        port:
          default: 0
          description: valid port number in range 1..65535
          format: int32
          type: integer
      type: object
    Resigning:
      properties:
        biometrics:
          default: true
          description: whether to enable biometrics
          nullable: true
          type: boolean
        group_directory:
          default: false
          description: whether to enable group directory access
          nullable: true
          type: boolean
        image_injection:
          default: true
          description: Whether to enable image injection
          nullable: true
          type: boolean
        sys_alerts_delay:
          default: false
          description: whether to delay system alerts
          nullable: true
          type: boolean
      type: object
  securitySchemes:
    basicAuth:
      scheme: basic
      type: http
    bearerAuth:
      bearerFormat: JWT
      scheme: bearer
      type: http
info:
  title: App Storage Service API
  version: 1.0.0
openapi: 3.0.0
paths:
  /v1/storage/download/{file_id}:
    get:
      parameters:
      - description: ID of file that needs to be fetched
        explode: false
        in: path
        name: file_id
        required: true
        schema:
          type: string
        style: simple
      responses:
        '200':
          content:
            application/octet-stream:
              schema:
                format: binary
                type: string
          description: successful operation
        '304':
          description: the file has been already cached on the client side
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the file with the given ID has not been found or is expired
        '412':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user is not in xTM
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to download the files previously uploaded to
        the storage.
      tags:
      - Download File
  /v1/storage/files:
    get:
      parameters:
      - description: one or more file ids to be listed
        explode: true
        in: query
        name: file_id
        required: false
        schema:
          items:
            type: string
          type: array
        style: form
      - description: one or more team ids the listed file(s) should be shared with
        explode: true
        in: query
        name: team_id
        required: false
        schema:
          items:
            type: string
          type: array
        style: form
      - description: one or more org ids the listed file(s) should be shared with
        explode: true
        in: query
        name: org_id
        required: false
        schema:
          items:
            type: string
          type: array
        style: form
      - description: the search term. The lookup is done using version names, codes,
          app names, identifiers and file names
        explode: true
        in: query
        name: q
        required: false
        schema:
          type: string
        style: form
      - description: one or more platform types
        explode: true
        in: query
        name: kind
        required: false
        schema:
          items:
            $ref: '#/components/schemas/Kind'
          type: array
        style: form
      - description: the number of the current page to show
        explode: true
        in: query
        name: page
        required: false
        schema:
          default: 1
          format: int32
          minimum: 1
          type: integer
        style: form
      - description: the number of items per page
        explode: true
        in: query
        name: per_page
        required: false
        schema:
          default: 25
          format: int32
          maximum: 100
          minimum: 1
          type: integer
        style: form
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  items:
                    description: The list of found files
                    items:
                      $ref: '#/components/schemas/File'
                    type: array
                  links:
                    $ref: '#/components/schemas/Links'
                    description: pagination links
                  page:
                    description: the number of the current page
                    format: int32
                    type: integer
                  per_page:
                    description: the maximum count of items per page
                    format: int32
                    type: integer
                  total_items:
                    description: the total count of found items
                    format: int64
                    type: integer
                type: object
          description: successful operation
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '412':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user is not in xTM
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to list files previously uploaded to the storage.
      tags:
      - List Files
  /v1/storage/files/{file_id}:
    delete:
      parameters:
      - description: file id to be deleted
        explode: false
        in: path
        name: file_id
        required: true
        schema:
          type: string
        style: simple
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  item:
                    $ref: '#/components/schemas/File'
                    description: The model of the deleted file
                type: object
          description: successful operation
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the file either does not exist or has been already deleted
        '412':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user is not in xTM
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to delete files that are accessible for the requester.
      tags:
      - Delete File
    put:
      parameters:
      - description: file id to be edited
        explode: false
        in: path
        name: file_id
        required: true
        schema:
          type: string
        style: simple
      requestBody:
        content:
          application/json:
            schema:
              properties:
                item:
                  $ref: '#/components/schemas/EditableFileProperties'
                  description: the actual file properties
              type: object
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  changed:
                    description: True if any of the file fields has been actually
                      changed
                    type: boolean
                  item:
                    $ref: '#/components/schemas/File'
                    description: The model of the changed file
                type: object
          description: successful operation
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if the provided file properties are invalid
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the file either does not exist or has been already deleted
        '412':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user is not in xTM
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to edit files that are accessible for the requester.
      tags:
      - Edit File
  /v1/storage/groups:
    get:
      parameters:
      - description: one or more group ids to be listed
        explode: true
        in: query
        name: group_id
        required: false
        schema:
          items:
            type: string
          type: array
        style: form
      - description: the search term (includes version names, codes, app names, identifiers,
          file and group names).
        explode: true
        in: query
        name: q
        required: false
        schema:
          type: string
        style: form
      - description: one or more application types
        explode: true
        in: query
        name: kind
        required: false
        schema:
          items:
            $ref: '#/components/schemas/Kind'
          type: array
        style: form
      - description: the number of the current page to show
        explode: true
        in: query
        name: page
        required: false
        schema:
          default: 1
          format: int32
          minimum: 1
          type: integer
        style: form
      - description: the number of items per page
        explode: true
        in: query
        name: per_page
        required: false
        schema:
          default: 25
          format: int32
          maximum: 100
          minimum: 1
          type: integer
        style: form
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  items:
                    description: the list of found items
                    items:
                      $ref: '#/components/schemas/Group'
                    type: array
                  links:
                    $ref: '#/components/schemas/Links'
                  page:
                    description: the number of the current page
                    type: integer
                  per_page:
                    description: the maximum count of items per page
                    type: integer
                  total_items:
                    description: the total count of found items
                    type: integer
                type: object
          description: successful operation
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '412':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user is not in xTM
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to list files previously uploaded to the storage.
      tags:
      - List Groups
  /v1/storage/groups/{group_id}:
    delete:
      parameters:
      - description: group id to be deleted
        explode: false
        in: path
        name: group_id
        required: true
        schema:
          format: int64
          type: integer
        style: simple
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  item:
                    $ref: '#/components/schemas/Group'
                    description: The model of the deleted group
                type: object
          description: successful operation
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user has no permissions to delete the group
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the group either does not exist or has been already deleted
        '412':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user is not in xTM
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to delete groups that are accessible for the
        requester.
      tags:
      - Delete Group
  /v1/storage/groups/{group_id}/settings:
    get:
      description: This end-point allows to retrieve settings from an accessible and
        existing group
      parameters:
      - description: ID of group whose settings need to be fetched
        explode: false
        in: path
        name: group_id
        required: true
        schema:
          format: int64
          type: integer
        style: simple
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  identifier:
                    description: the identifier of the app container by the group.
                      Could be null for non-app groups
                    nullable: true
                    type: string
                  kind:
                    $ref: '#/components/schemas/Kind'
                    description: group platform name
                  settings:
                    description: The actual group settings. null is returned if the
                      group is not an app group
                    nullable: true
                    oneOf:
                    - $ref: '#/components/schemas/AndroidSettings'
                    - $ref: '#/components/schemas/IOSSettings'
                type: object
          description: successful operation
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if the group does not exist or is not accessible
      tags:
      - Get Group Settings
    put:
      parameters:
      - description: ID of group whose settings need to be fetched
        explode: false
        in: path
        name: group_id
        required: true
        schema:
          format: int64
          type: integer
        style: simple
      requestBody:
        content:
          application/json:
            schema:
              properties:
                settings:
                  description: the actual group settings
                  oneOf:
                  - $ref: '#/components/schemas/AndroidSettings'
                  - $ref: '#/components/schemas/IOSSettings'
              type: object
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  identifier:
                    description: the identifier of the app container by the group
                    type: string
                  kind:
                    $ref: '#/components/schemas/Kind'
                    description: group platform name
                  settings:
                    description: the actual group settings
                    oneOf:
                    - $ref: '#/components/schemas/AndroidSettings'
                    - $ref: '#/components/schemas/IOSSettings'
                type: object
          description: successful operation
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if the provided group identifier is not a valid one or the
            provided settings object is invalid
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if the current user does not have enough permissions to change
            the group
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if the group does not exist or is not accessible
        '406':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if the settings cannot be set for the given group type
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to set settings for an existing and accessible
        group
      tags:
      - Set Group Settings
  /v1/storage/info:
    get:
      parameters: []
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  expiration_timeout_sec:
                    description: The count of seconds until the newly added file expires
                      after being uploaded
                    format: int64
                    type: integer
                type: object
          description: successful operation
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to retrieve the current service configuration.
      tags:
      - Get Service Info
  /v1/storage/upload:
    post:
      parameters: []
      requestBody:
        content:
          multipart/form-data:
            schema:
              properties:
                description:
                  description: an optional custom file description string
                  maxLength: 255
                  nullable: true
                  type: string
                name:
                  description: the file name (if unset then will be retrieved from
                    `content-disposition` header)
                  maxLength: 255
                  type: string
                payload:
                  description: the content of the file to be uploaded
                  format: binary
                  type: string
              required:
              - payload
              type: object
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                properties:
                  item:
                    $ref: '#/components/schemas/File'
                type: object
          description: successful operation
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: either the incoming parameters are invalid or missing
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: authorization failed
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user has no permissions to share the file with
            the requested org units
        '406':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if the script fails to parse the metadata from the given application
        '412':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the current user is not in xTM
        '413':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: the file size of the payload exceeds the maximum file size
            limit
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: if there are no more free upload slots
      security:
      - bearerAuth: []
      - basicAuth: []
      summary: This end-point allows to upload files to the storage service.
      tags:
      - Upload File
servers:
- description: Environment
  url: https://xxx.saucelabs.net

Full region name responds with DNS error

Short summary of what the user sees:
If a user tries to to use a region name that is not the "short" version it will fail

Exact steps to reproduce the problem:

  1. Download latest version of saucelabs module (at time of bug report 2.1.8)
  2. Try running any command via CLI or as module with a region that is not eu or us.
    Example:
    sl listJobs $SAUCE_USERNAME --limit 5 --region us-central-1

Isolation: What must be true for it to happen? When does it not happen?
Seems to only happen if you use the full region name.

Links to Relevant Test Archives or Logs:

โžœ  ~ sl listJobs $SAUCE_USERNAME --limit 5 --region us-central-1
{ Error: getaddrinfo ENOTFOUND us-west-1.saucelabs.com us-west-1.saucelabs.com:443
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'us-west-1.saucelabs.com',
  host: 'us-west-1.saucelabs.com',
  port: 443 }
โžœ  ~ sl listJobs $SAUCE_USERNAME --limit 5 --region us-west-1
{ Error: getaddrinfo ENOTFOUND us-west-1.saucelabs.com us-west-1.saucelabs.com:443
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'us-west-1.saucelabs.com',
  host: 'us-west-1.saucelabs.com',
  port: 443 }

What attempts were made to find the root cause so far?
This might be due to how we use the REGION_MAPPINGS and how we determine the correct DC.

export const REGION_MAPPING = {

if (!headless && hostname.split('.').length > 2) {
subdomain = hostname.split('.')[0] + '.'
hostname = hostname.split('.').slice(-2).join('.')
} else if (!headless && region === 'us') {
locale = ''
}
return protocol + subdomain + locale + hostname
}

us-west-1.saucelabs.com doesn't work (not sure if intended) but eu-central-1.saucelabs.com does.
We could have us-west-1 default to saucelabs.com or app.saucelabs.com and have eu-central-1 just append the name.

Error: failed to check for existing tunnels

I'm using @web/test-runner-saucelabs and today my builds started to fail with the following error:

[Saucelabs] Setting up Sauce Connect proxy...
3 Nov 15:19:00 - Sauce Connect 4.6.2, build 5183 ad61662

3 Nov 15:19:00 - REST: Using CA certificate bundle /usr/local/etc/openssl/cert.pem.
3 Nov 15:19:00 - REST: Using CA certificate verify path /etc/ssl/certs.

3 Nov 15:19:00 - TUNNEL: Using CA certificate bundle /usr/local/etc/openssl/cert.pem.

3 Nov 15:19:00 - TUNNEL: Using CA certificate verify path /etc/ssl/certs.

3 Nov 15:19:00 - Starting up; pid 96701

3 Nov 15:19:00 - Command line arguments: /Users/XXXX/vaadin/vaadin-time-picker-new/node_modules/saucelabs/build/.sc-v4.6.2/bin/sc --tunnel-identifier=web-test-runner-632c299d-5745-4809-89a9-9f6250d86cf2 --no-ssl-bump-domains=127.0.0.1,localhost,10.64.12.198 --user=XXXXXX-XXXXXXXX --api-key=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX --rest-url=https://api.us-west-1.saucelabs.com/rest/v1

3 Nov 15:19:00 - Log file: /var/folders/45/94scl3_d1wx4lslst2rv0jq80000gn/T/sc-web-test-runner-632c299d-5745-4809-89a9-9f6250d86cf2.log

3 Nov 15:19:00 - Pid file: /tmp/sc_client-web-test-runner-632c299d-5745-4809-89a9-9f6250d86cf2.pid
3 Nov 15:19:00 - Timezone: EET GMT offset: 2h

3 Nov 15:19:00 - Using no proxy for connecting to Sauce Labs REST API.

3 Nov 15:19:01 - Started scproxy on port 53014.

3 Nov 15:19:01 - Please wait for 'you may start your tests' to start your tests.

3 Nov 15:19:03 - failed to check for existing tunnels

3 Nov 15:19:03 - Sauce Connect could not establish a connection.
3 Nov 15:19:03 - Please check your firewall and proxy settings.

Error while running tests:
Error: 3 Nov 15:19:03 - Sauce Connect could not establish a connection.
3 Nov 15:19:03 - Please check your firewall and proxy settings.

    at Socket.<anonymous> (/Users/sergey/vaadin/vaadin-time-picker-new/node_modules/saucelabs/build/index.js:318:25)
    at Socket.emit (events.js:315:20)
    at addChunk (_stream_readable.js:295:12)
    at readableAddChunk (_stream_readable.js:271:9)
    at Socket.Readable.push (_stream_readable.js:212:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:186:23)

Build example: https://github.com/vaadin/vaadin-time-picker/pull/168/checks?check_run_id=1347582686

Note, the repository also has other job (visual regression tests) that uses legacy URL and it works fine:
https://github.com/vaadin/vaadin-time-picker/pull/168/checks?check_run_id=1347582625

Issue creating sauce connect tunnel for real mobile devices

I see the issue creating sauce connect tunnel for real mobile devices. It's happening due to duplication of api key argument in sauce connect command being generated when custom api key provided to create tunnel for real device testing.

Code Block

    const sc = await myAccount.startSauceConnect({
        /**
         * you can pass in a `logger` method to print Sauce Connect log messages
         */
        logger: (stdout) => console.log(stdout),
        /**
         * see all available parameters here: https://wiki.saucelabs.com/display/DOCS/Sauce+Connect+Proxy+Command-Line+Quick+Reference+Guide
         * all parameters have to be applied camel cased instead of with hyphens, e.g.
         * to apply the `--tunnel-identifier` parameter, set:
         */
        restUrl: 'https://us1.api.testobject.com/sc/rest/v1',
        apiKey: 'XXXCustomAPIKeyProvidedXXX',
        tunnelIdentifier: 'myTunnel',
        noSslBumpDomains: '*.example.com'
    })

Sauce Connect command generated

7 Jul 01:58:29 - Command line arguments: C:\Users\Sitam\Desktop\sauce-labs\node_modules\saucelabs\build\.sc-v4.5.4\bin\sc.exe --rest-url=https://us1.api.testobject.com/sc/rest/v1 --api-key=XXXCustomAPIKeyProvidedXXX --tunnel-identifier=myTunnel --no-ssl-bump-domains=*.example.com --user=xxx --api-key=XXXDefaultAPIKeyAddedXXX

Please notice the duplicate --api-key argument above which is causing trouble here.

Embed Sauce Connect support

There is no reason to have a separate package to use Sauce Connect. We should embed this functionality into this package. It should ensure to always use the latest SC version and only download it when needed and not available.

Periodic ENOENT running in CI

This is an error that happens >50% of the time on CircleCI. No changes are made between one run and the next. One run might pass, the next will fail with this error. All versions are committed in yarn.lock.

12 06 2020 08:29:13.851:ERROR [SaucelabsLauncher]: Error: spawn /home/circleci/repo/node_modules/saucelabs/build/.sc-v4.5.4/bin/sc ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:268:19)
    at onErrorNT (internal/child_process.js:468:16)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)

{
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn /home/circleci/repo/node_modules/saucelabs/build/.sc-v4.5.4/bin/sc',
  path: '/home/circleci/repo/node_modules/saucelabs/build/.sc-v4.5.4/bin/sc',
  spawnargs: [ '--version' ],
  killed: false,
  stdout: '',
  stderr: '',
  failed: true,
  signal: null,
  cmd: '/home/circleci/repo/node_modules/saucelabs/build/.sc-v4.5.4/bin/sc --version',
  timedOut: false
}

Add getUserConcurrency to api

REST API: users/:username/concurrency
The result shows real-time numbers for the parent account and all of its sub-accounts. There is also a "totals" section at the end which tallies the numbers across all accounts.

license?

which license is this released under?

replacement for old getAllBrowsers (endpoint: info/browsers/all)

with v1.x there was a route available to list all possible browser combinations.
We've made use of that for our endpoints builder.

The return was an array of simple browser descriptions:

{
    "short_version": "27",
    "long_name": "Google Chrome",
    "api_name": "chrome",
    "long_version": "27.0.1453.110.",
    "latest_stable_version": "27",
    "automation_backend": "webdriver",
    "os": "Mac 10.13"
},

With the 2x branch I can't any longer find that path (info/browsers/all). Is there an alternative API endpoint now available for that?

Furthermore the new API should list that by region

Saucelabs always exports ./lib-cov/SauceLabs as default module

Inside index.js saucelabs has these lines of code-
module.exports = process.env.SAUCELABS_COV ? require('./lib-cov/SauceLabs') : require('./lib/SauceLabs');
but whatever change we make ./lib-cov/SauceLabs is getting exported as the default module.

We are at node version 8

Sauce Connect breaks on Windows

When running on Windows, I think the below line is breaking Sauce Connect. Isn't path.join() intended for file system paths?

https://github.com/saucelabs/node-saucelabs/blob/master/src/utils.js#L42

Note the \ in the --rest-url param below.

2020-05-29 20:58:58.246 [5940] Sauce Connect 4.6.1, build 5158 da2fb0c 
2020-05-29 20:58:58.248 [5940] Proxy autodetection disabled
2020-05-29 20:58:58.249 [5940] Starting up; pid 5940
2020-05-29 20:58:58.249 [5940] Command line arguments: C:\Users\foo\bar\node_modules\saucelabs\build\.sc-v4.6.1\bin\sc.exe --no-autodetect=true --tunnel-identifier=SC-tunnel-18283389594820365 --user=xxx --api-key=xxx --rest-url=https://api.us-west-1.saucelabs.com\rest/v1 
...
2020-05-29 20:58:58.962 [5940] PROXY *** scproxy started ***
2020-05-29 20:58:59.028 [5940] PROXY found DNS server 192.168.0.1
2020-05-29 20:58:59.029 [5940] PROXY found DNS server 8.8.4.4
2020-05-29 20:58:59.031 [5940] PROXY found DNS server 8.8.8.8
2020-05-29 20:58:59.113 [5940] Started scproxy on port 50789.
2020-05-29 20:58:59.113 [5940] Please wait for 'you may start your tests' to start your tests.
2020-05-29 20:58:59.114 [5940] failed to check for existing tunnels
2020-05-29 20:58:59.114 [5940] Sauce Connect could not establish a connection.
2020-05-29 20:58:59.114 [5940] Please check your firewall and proxy settings.
2020-05-29 20:58:59.115 [5940] Goodbye.

Additionally, trying to override the REST endpoint with the restUrl option does not work as the override is placed before the broken --rest-url parameter.

2020-05-29 21:09:27.601 [864] Sauce Connect 4.6.1, build 5158 da2fb0c 
2020-05-29 21:09:27.603 [864] Proxy autodetection disabled
2020-05-29 21:09:27.603 [864] Starting up; pid 864
2020-05-29 21:09:27.603 [864] Command line arguments: C:\Users\foo\bar\node_modules\saucelabs\build\.sc-v4.6.1\bin\sc.exe --no-autodetect=true --tunnel-identifier=SC-tunnel-46903707710273035 --rest-url=https://api.eu-central-1.saucelabs.com/rest/v1 --user=xxx --api-key=xxx --rest-url=https://api.us-west-1.saucelabs.com\rest/v1 
...
2020-05-29 21:09:28.265 [864] PROXY *** scproxy started ***
2020-05-29 21:09:28.297 [864] PROXY found DNS server 192.168.0.1
2020-05-29 21:09:28.298 [864] PROXY found DNS server 8.8.4.4
2020-05-29 21:09:28.299 [864] PROXY found DNS server 8.8.8.8
2020-05-29 21:09:28.366 [864] Started scproxy on port 51007.
2020-05-29 21:09:28.366 [864] Please wait for 'you may start your tests' to start your tests.
2020-05-29 21:09:28.366 [864] failed to check for existing tunnels
2020-05-29 21:09:28.366 [864] Sauce Connect could not establish a connection.
2020-05-29 21:09:28.366 [864] Please check your firewall and proxy settings.
2020-05-29 21:09:28.366 [864] Goodbye.

need support for share tunnels

Hi,
Your package is awesome, we use it to connect saucelabs and run out tests. But recently, we changed the infra and setup shared tunnel so that teams could run tests with shared tunnels in pool.

But with your package, seems it does not support shared tunnel. I need this feature very much.

job status updates for firefox

updateJob(username, sessionId, status) is unable to update the status for firefox browser though it is working fine with chrome browser.

3.1.1 release seems broken

Was the publish of version 3.1.1 a mistake?

I don't see that release in the master branch commit history.
Also, there's no 3.1.0 release on npm.
Also also, there's a 3.1.1 alpha release that is more recent than the actual 3.1.1 release.
(Ref: https://www.npmjs.com/package/saucelabs?activeTab=versions)

Moreover, projects that pull it in are seeing Error: connect ECONNREFUSED 127.0.0.1:3000 when their test-runner tries to update job details. Rather than hitting the Saucelabs API, it's trying to hit:
http://localhost:3000/v1/****/jobs/[jobId]

Thanks!

Examples on build pass/fail reporting

Could you add some example of how to send back to sauce the pass/fail status so the SauceLabs badge can be updated. I tried the CURL variant and it bugs, would be nice to be able to do it in Node instead.

I write this request after failing noobish on sending back to Sauce the build pass/fail info. Is updateJob() the way here? when to call it? I suppose inside My Gruntfile is too early :P

Thanks!

As npm package sample is wrong

Hey there,

looking at the sample provided with the latest update (after taking over the package) this clearly can't build. Where is that user coming from? Besides that the SauceLabs constructor expects a options object specifying the user and key aka accesskey as minimum.

What I wonder is that now most APIs do require the username. Why isn't that already forwarded from the provided options config?

Add more single job methods

I'd love to add getJobAssetFiles to the prototype. This and a few other job methods available in the api are not yet in this wrapper:

SauceLabs.prototype.getJobAssetFiles = function (id, filename, callback) {
    this.send({
        method: 'GET',
        path: ':username/jobs/:id/assets/:filename',
        args: { id: id, filename: filename },
    }, callback);
};

Add TypeScript Definitions

TypeScript-based consumers of node-saucelabs could use TypeScript definitions. Currently, an instance of node-saucelabs can only be typed as the general any.

Some projects include their own d.ts files, but that's typically done if the code is TypeScript-based. In the case of node-saucelabs, adding a definition to the DefinitelyTyped repo would be more appropriate, which would allow for @types/node-saucelabs to be installed from npm.

Support for Sauce Connect for real mobile devices

I am not able to make sauce connect tunnel work for real mobile devices (https://app.testobject.com/). When I try to set custom restUrl and apiKey inside myAccount.startSauceConnect(), it doesn't work. My setup looks like below:

    const sc = await myAccount.startSauceConnect({
        /**
         * you can pass in a `logger` method to print Sauce Connect log messages
         */
        logger: (stdout) => console.log(stdout),
        /**
         * see all available parameters here: https://wiki.saucelabs.com/display/DOCS/Sauce+Connect+Proxy+Command-Line+Quick+Reference+Guide
         * all parameters have to be applied camel cased instead of with hyphens, e.g.
         * to apply the `--tunnel-identifier` parameter, set:
         */
        restUrl: 'https://us1.api.testobject.com/sc/rest/v1',
        apiKey: 'XXXXXXXXXXXX',
        tunnelIdentifier: 'myTunnel'
    })

When looked at sc command executed, it seems to be duplicating --rest-url and --api-key options in the command and failed to start the tunnel. Command generated by sc as below -
C:\project\tests\node_modules\saucelabs\build\.sc-v4.5.4\bin\sc.exe --rest-url=https://us1.api.testobject.com/sc/rest/v1 --api-key=XXXXXXXXXXXX --tunnel-identifier=myTunnel --user=xxx --api-key=a123-xxx-5ty-yyy --rest-url=https://api.us-west-1.saucelabs.com\rest/v1

Please help to resolve the issue.

Platform Configurator Copy Code section scrolls erroneously for Chrome

Unable to fetch values from any tab other than Java for following config.
MacOSX
Chrome 76.0
Tried for following config:
Screen Shot 2019-09-02 at 2 06 42 PM

caps['browserName'] = 'Safari';
caps['appiumVersion'] = '1.8.1';
caps['deviceName'] = 'iPad Pro (9.7 inch) Simulator';
caps['deviceOrientation'] = 'portrait';
caps['platformVersion'] = '11.2';
caps['platformName'] = 'iOS';

CLI erroring out with "Error: Couldn't find API endpoint for command "then"" on 4.0.0

Short summary of what the user sees:
Any CLI command will not work when using 4.0.0

Exact steps to reproduce the problem:
Download latest version (4.0.0)
After building and compiling run:

./bin/sl getStatus

See error. This happens with other commands like downloadJobAsset and from my testing all commands are affected.
Isolation: What must be true for it to happen? When does it not happen?
Happens consistently.
I was using Node v12.13.0 but was seen using v10.15.3 too

Links to Relevant Test Archives or Logs:
Full stacktrace:

/Users/enriquegonzalez/git/node-saucelabs/src/index.js:78
            throw new Error(`Couldn't find API endpoint for command "${propName}"`)
                  ^
Error: Couldn't find API endpoint for command "then"
    at SauceLabs.get (/Users/enriquegonzalez/git/node-saucelabs/src/index.js:78:19)
    at isPromise (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/lib/is-promise.js:2:43)
    at Object.runCommand (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/lib/command.js:244:11)
    at Object.parseArgs [as _parseArgs] (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/yargs.js:1154:41)
    at Object.argv (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/yargs.js:1088:21)
    at Object.run (/Users/enriquegonzalez/git/node-saucelabs/src/cli.js:71:17)
    at Object.<anonymous> (/Users/enriquegonzalez/git/node-saucelabs/bin/sl:3:25)
    at Module._compile (internal/modules/cjs/loader.js:956:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
    at Module.load (internal/modules/cjs/loader.js:812:32)

What attempts were made to find the root cause so far?
From what I could tell the wrong prop could be passed here:
https://github.com/saucelabs/node-saucelabs/blob/master/src/index.js#L37

If I change the _ to a variable and print it out it comes out as an Object with:

/Users/enriquegonzalez/git/node-saucelabs/src/utils.js:65
  key: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXX${scope._accessKey.slice(-6)}',
                                                         ^
TypeError: Cannot read property 'slice' of undefined
    at toString (/Users/enriquegonzalez/git/node-saucelabs/src/utils.js:65:58)
    at SauceLabs.get (/Users/enriquegonzalez/git/node-saucelabs/src/index.js:78:29)
    at isPromise (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/lib/is-promise.js:2:43)
    at Object.runCommand (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/lib/command.js:244:11)
    at Object.parseArgs [as _parseArgs] (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/yargs.js:1154:41)
    at Object.argv (/Users/enriquegonzalez/git/node-saucelabs/node_modules/yargs/yargs.js:1088:21)
    at Object.run (/Users/enriquegonzalez/git/node-saucelabs/src/cli.js:71:17)
    at Object.<anonymous> (/Users/enriquegonzalez/git/node-saucelabs/bin/sl:3:25)
    at Module._compile (internal/modules/cjs/loader.js:956:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)

Saucelabs taking ownership of this module

Hey @unindented / @OniOni / @PhearZero

Saucelabs approached me about taking ownership of the module. I don't use Saucelabs any more and they want to bring it up to scratch with what they have on offer. I have no issue with transferring the module to the saucelabs org and I'm guessing none of you do too but I wanted to ask publicly if you did before I did it.

downloadJobAsset() method doesn't create video when path is not specified

Current behaviour:
When calling

await myAccount.downloadJobAsset( 'job_id', 'video.mp4' )

the asset is not downloaded in the current working directory.

When I added directory with the filename
await myAccount.downloadJobAsset( 'job_id', 'video.mp4', './video.mp4' )

asset got created in the cwd.
It would be great if no directory specified it defaults to cwd, otherwise use specific one.

SauceLabs module should provide RateLimit headers to downstream libraries

As part of a project, I'm using SauceLabs to test some code. SauceLabs recently announced they are rate limiting the number of API calls to their services.

http://sauceio.com/index.php/2016/02/announcing-new-rest-api-usage-limits/

One thing we wanted to do was to monitor the usage of the API calls and throw a warning if we are coming close to hitting the limits. However the SauceLabs library only provides the parsed JSON, not any of the headers (including the Rate Limit data).

The function that seems to be impacted by this is makeRequest in SauceLabs.js. Is there any easy way to provide the X-Ratelimit header data along with the JSON parsed response?

Need a SauceLab tool for CI

Hi guys,

Our company is looking for a tool to run tests along with deployments. We are aiming to have a system that would run a serie of screenshots before deployment, and another one after deployment, and ultimately diff those images.

This is the ultimate goal, but we set a few steps along the way, as such :

  1. Just get screenshots of the website after deployment
    2.Get screenshots twice (before and after deployment), compare images and implement a comparison configuration file
  2. Expose a nice UI through a webserver

We will base our work on SauceLabs as we get the license, and want to code this tool in NodeJS.

So I was wondering if you would like to add these (or part of these) cool features in this project or if this aims to be just what it is (an API wrapper) with no more complex layer around it ?

At first, I thought about developing the tool using this lib as a dependency but if you want to go further down the SauceLab hole there, we could join the project too.

Let me know, in any case, thank you for the good work you did there,
++

Fetching list of active tunnels by user

Hello,

While using the Rest API I could able to pull the active tunnels by username

Request: rest/v1/USERNAME/tunnels
Response: ['tunnel-id-1','tunnel-id-2']

But while using the node module, I'm getting the information from all the users under the organization. Is it because of the user being admin?

Request: api.listAvailableTunnels(USERNAME)
Response:

{ "user-1": [], "user-2":[]}

Reference picture of fetching available tunnels
https://share.getcloudapp.com/BluJkZOJ

Failure on M1 Mac: unexpected signal during runtime execution

Hello,

On my MacBook M1 there is a following error when using @web/test-runner-saucelabs:

Error: fatal error: unexpected signal during runtime execution

    at Socket.<anonymous> (/Users/serhii/vaadin/web-components/node_modules/saucelabs/build/index.js:307:16)
    at Socket.emit (events.js:314:20)
    at Socket.EventEmitter.emit (domain.js:483:12)
    at addChunk (_stream_readable.js:297:12)
    at readableAddChunk (_stream_readable.js:272:9)
    at Socket.Readable.push (_stream_readable.js:213:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:188:23)

Any ideas what the reason could be?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.