Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugin-cc): Enable coverage #3939

Merged
merged 1 commit into from
Oct 24, 2024

Conversation

Kesari3008
Copy link
Contributor

@Kesari3008 Kesari3008 commented Oct 24, 2024

COMPLETES #AD-HOC

This pull request addresses

Enables unit test coverage for the code

by making the following changes

Updated jest config to set collectCoverage property to true.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

Ran the yarn run test:unit command and coverage report generated.

Screenshot 2024-10-24 at 11 57 02 AM Screenshot 2024-10-24 at 11 57 07 AM Screenshot 2024-10-24 at 11 57 12 AM

I certified that

  • I have read and followed contributing guidelines

  • I discussed changes with code owners prior to submitting this pull request

  • I have not skipped any automated checks

  • All existing and new tests passed

  • I have updated the documentation accordingly


Make sure to have followed the contributing guidelines before submitting.

Summary by CodeRabbit

  • New Features

    • Introduced a new "Contact Center" sample application with improved navigation options.
    • Added WebSocket functionality for managing connections and events in the Contact Center.
    • Implemented a comprehensive ContactCenter class for handling contact center operations.
  • Documentation

    • Updated README.md for the @webex/plugin-cc package with sections on getting started, development, and usage.
    • Added detailed comments and structure for the new Contact Center sample.
  • Bug Fixes

    • Enhanced error handling and robustness in WebSocket and service URL functionalities.
  • Tests

    • Expanded test coverage for the WebSocket and ContactCenter classes, including edge cases and error handling scenarios.

@Kesari3008 Kesari3008 added the validated If the pull request is validated for automation. label Oct 24, 2024
@Kesari3008 Kesari3008 requested review from a team as code owners October 24, 2024 06:33
Copy link

coderabbitai bot commented Oct 24, 2024

Walkthrough

The pull request introduces several changes across multiple files, primarily focusing on the addition of a new Contact Center feature within the Webex SDK. Key modifications include the addition of new HTML and JavaScript files for the Contact Center sample application, enhancements to the Mercury and Socket classes to improve connection handling, and the introduction of a new WebSocket class. Additionally, a new README and configuration files for the Contact Center plugin have been created, along with updates to existing files to integrate this new functionality into the Webex framework.

Changes

File Change Summary
docs/index.html Added a new link to the "Contact Center" sample in the Samples section.
docs/samples/contact-center/app.js Introduced a new web application for a contact center using the Webex SDK, managing authentication and registration.
docs/samples/contact-center/index.html Created a new HTML file for the Contact Center sample with authentication and registration functionalities.
docs/samples/contact-center/style.css Added styles for the Contact Center application, defining layout and UI components.
packages/@webex/internal-plugin-mercury/src/mercury.js Enhanced the Mercury class with new properties and improved error handling and connection logic.
packages/@webex/internal-plugin-mercury/src/socket/socket-base.js Updated the Socket class to include new parameters for authorization and acknowledgment in the open method.
packages/@webex/internal-plugin-mercury/test/unit/spec/mercury.js Added new tests for the Mercury class, focusing on connection handling and error scenarios.
packages/@webex/internal-plugin-mercury/test/unit/spec/socket.js Expanded tests for the Socket class to validate new options and behaviors.
packages/@webex/plugin-cc/README.md Created a new README file for the Contact Center plugin with sections for getting started, developing, and testing.
packages/@webex/plugin-cc/babel.config.json Added a Babel configuration file for the Contact Center plugin to support JavaScript and TypeScript.
packages/@webex/plugin-cc/jest.config.js Introduced a Jest configuration file for the Contact Center plugin, including coverage and reporting settings.
packages/@webex/plugin-cc/package.json Created a package.json file for the Contact Center plugin, defining metadata and dependencies.
packages/@webex/plugin-cc/src/WebSocket/WebSocket.ts Added a new WebSocket class for managing WebSocket connections and subscriptions.
packages/@webex/plugin-cc/src/WebSocket/config.ts Introduced a configuration object for WebSocket connection parameters.
packages/@webex/plugin-cc/src/WebSocket/types.ts Added a new interface for WebSocket management methods.
packages/@webex/plugin-cc/src/cc.ts Created a ContactCenter class for managing connections to the contact center service.
packages/@webex/plugin-cc/src/config.ts Introduced a configuration object for the Contact Center plugin.
packages/@webex/plugin-cc/src/constants.ts Added several constants for use within the Contact Center plugin.
packages/@webex/plugin-cc/src/index.ts Registered the Contact Center plugin within the Webex framework.
packages/@webex/plugin-cc/src/types.ts Introduced new types and interfaces for the Contact Center plugin.
packages/@webex/plugin-cc/test/unit/spec/WebSocket.ts Added unit tests for the WebSocket class, covering various functionalities.
packages/@webex/plugin-cc/test/unit/spec/cc.ts Created unit tests for the Contact Center integration, validating various methods and behaviors.
packages/@webex/plugin-cc/tsconfig.json Added a TypeScript configuration file for the Contact Center plugin.
packages/@webex/test-helper-mock-webex/src/index.js Updated to include 'cc' in the nonInternalPlugins array for proper handling in mock instances.
packages/@webex/webex-core/src/lib/services/service-catalog.js Enhanced the findServiceUrlFromUrl method for better URL matching and error handling.
packages/@webex/webex-core/test/unit/spec/services/service-catalog.js Updated tests for the ServiceCatalog class to validate new URL handling logic.
packages/webex/package.json Updated to include the new Contact Center module in exports and dependencies.
packages/webex/src/contact-center.js Introduced a new Webex module for the Contact Center, initializing with necessary configurations.
packages/webex/src/webex.js Added a requirement for the @webex/plugin-cc module.
tooling/lib/build.js Updated the buildSamples function to clean up previous sample files before building.
webpack.config.js Added a new entry for the Contact Center in the Webpack configuration.

Poem

🐰 In the garden of code, changes bloom bright,
A Contact Center shines, a new guiding light.
With WebSocket whispers and samples to share,
The SDK's magic dances in the air.
So hop along, friends, let’s explore and play,
In this world of tech, we’ll find our way! 🌼✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Kesari3008 Kesari3008 changed the base branch from next to feat/wxcc October 24, 2024 06:34
@Kesari3008 Kesari3008 enabled auto-merge (squash) October 24, 2024 06:40
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (58)
packages/@webex/plugin-cc/src/index.ts (1)

6-8: 💡 Codebase verification

Based on the analysis of the test files, I can now provide the final response:

Add missing test coverage for plugin registration

The current test suite in packages/@webex/plugin-cc/test/unit/spec/cc.ts focuses on testing the ContactCenter class functionality but lacks specific tests for plugin registration. While it tests the initialization of the ContactCenter plugin through MockWebex, it doesn't verify:

  • The correct registration of the plugin with the name 'cc'
  • Proper passing of the config object during registration
  • Error handling during plugin registration

Suggested test locations to add:

  • packages/@webex/plugin-cc/test/unit/spec/index.ts (create this file for plugin registration tests)
  • Test scenarios should cover the registerPlugin call from src/index.ts
🔗 Analysis chain

Add test coverage for plugin registration.

Since we're enabling test coverage, ensure the following test scenarios are covered:

  1. Verify plugin registers with name 'cc'
  2. Verify config is properly passed to the plugin
  3. Test error handling for registration failures

Let's check if these test cases exist:


Let me check the content of the test file to see if it covers the plugin registration scenarios.


Let me check if there are any specific plugin registration tests in other test files, as the current test file focuses on the ContactCenter class functionality but not the plugin registration itself.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for existing test coverage of plugin registration
# Look for test files that might contain plugin registration tests
rg -l "registerPlugin.*cc.*ContactCenter" "packages/@webex/plugin-cc/test" || echo "No existing test coverage found for plugin registration"

Length of output: 301


Script:

#!/bin/bash
# Check the content of the test file
cat "packages/@webex/plugin-cc/test/unit/spec/cc.ts"

Length of output: 9291


Script:

#!/bin/bash
# Search for plugin registration tests in the entire test directory
rg -l "registerPlugin.*cc" packages/@webex/plugin-cc/test/

Length of output: 60

packages/@webex/plugin-cc/src/config.ts (2)

1-12: 🛠️ Refactor suggestion

Add TypeScript interface definitions for configuration.

The configuration object would benefit from explicit TypeScript interfaces to improve type safety and developer experience.

Consider adding interfaces before the export:

interface CCMetrics {
  clientName: string;
  clientType: string;
}

interface CCConfig {
  allowMultiLogin: boolean;
  clientType: string;
  isKeepAliveEnabled: boolean;
  force: boolean;
  metrics: CCMetrics;
}

interface Config {
  cc: CCConfig;
}

export default {
  // ... existing config
} as Config;

3-10: 🛠️ Refactor suggestion

Consider extracting string literals as constants.

String literals should be extracted as named constants for better maintainability and reuse.

Consider refactoring:

const CC_CLIENT_TYPE = 'WebexCCSDK';
const CC_CLIENT_NAME = 'WEBEX_JS_SDK';

export default {
  cc: {
    allowMultiLogin: true,
    clientType: CC_CLIENT_TYPE,
    isKeepAliveEnabled: false,
    force: true,
    metrics: {
      clientName: CC_CLIENT_NAME,
      clientType: CC_CLIENT_TYPE,
    },
  },
};
packages/webex/src/contact-center.js (2)

14-18: 🛠️ Refactor suggestion

Consider using an immutable approach to config merging.

The current implementation modifies the input parameter directly, requiring an eslint disable comment. Consider using an immutable approach instead:

-Webex.init = function init(attrs = {}) {
-  attrs.config = merge({}, config, attrs.config); // eslint-disable-line no-param-reassign
-
-  return new Webex(attrs);
-};
+Webex.init = function init(attrs = {}) {
+  return new Webex({
+    ...attrs,
+    config: merge({}, config, attrs.config)
+  });
+};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Webex.init = function init(attrs = {}) {
  return new Webex({
    ...attrs,
    config: merge({}, config, attrs.config)
  });
};

9-12: ⚠️ Potential issue

Add missing PACKAGE_VERSION import.

The code references PACKAGE_VERSION but it's not imported or defined. This could lead to undefined behavior.

Consider adding the import at the top of the file:

+import {version as PACKAGE_VERSION} from './package.json';

Or define it as a constant if it's meant to be injected during build:

+const PACKAGE_VERSION = process.env.PACKAGE_VERSION || '0.0.0';

Committable suggestion was skipped due to low confidence.

packages/@webex/plugin-cc/jest.config.js (2)

4-7: 🛠️ Refactor suggestion

Consider specifying transformIgnorePatterns

An empty transformIgnorePatterns array means Jest will transform all files, including those in node_modules. This could significantly impact test performance. Consider adding standard patterns:

-  transformIgnorePatterns: [],
+  transformIgnorePatterns: ['/node_modules/(?!@webex)'],

This pattern will only transform @webex packages while skipping other node_modules.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  rootDir: './',
  transformIgnorePatterns: ['/node_modules/(?!@webex)'],
  testPathIgnorePatterns: ['/node_modules/', '/dist/'],
  testResultsProcessor: 'jest-junit',

10-20: 💡 Codebase verification

Based on the gathered information, I can now generate the final response:

Consider a more gradual approach to coverage thresholds for this new package

The current implementation shows this is a newly created package (committed on Oct 23, 2024) with:

  • 8 source files requiring coverage
  • Only 2 test files currently present (test/unit/spec/WebSocket.ts and test/unit/spec/cc.ts)

Setting an 85% threshold across all metrics (lines, functions, branches, statements) immediately for a new package could:

  1. Block initial contributions and slow down development
  2. Lead to rushed test implementations just to meet the threshold
  3. Create maintenance overhead in early development phases

Recommendation:

  • Start with a lower initial threshold (e.g., 60-70%)
  • Gradually increase it through subsequent PRs as the implementation stabilizes
  • Consider different thresholds for different metrics (e.g., higher for lines/statements, lower for branches)
🔗 Analysis chain

Verify feasibility of 85% coverage threshold

While high coverage targets are admirable, an 85% threshold across all metrics (lines, functions, branches, statements) might be challenging to maintain, especially for a new plugin. Consider:

  1. Starting with a lower threshold and gradually increasing it
  2. Setting different thresholds for different metrics

Let me gather more information about the test coverage by examining the test files in more detail.

The previous results showed 8 source files but no test files with .test.ts or .spec.ts extensions. Let's check for tests with other naming patterns and understand if this is a new package, which would help us make a more informed decision about the coverage threshold.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check current test coverage in the codebase
# Test: Search for existing test files to assess coverage potential
echo "Checking test files distribution..."
fd -e test.ts -e spec.ts . packages/@webex/plugin-cc/
echo "Checking source files that need coverage..."
fd -e ts -e js . packages/@webex/plugin-cc/src/

Length of output: 632


Script:

#!/bin/bash
# Check if there are any existing test files in different locations
echo "Searching for test files in all possible locations..."
rg -l "describe|test\(" packages/@webex/plugin-cc/

# Check package.json for any test-related scripts
echo -e "\nChecking package.json for test scripts..."
cat packages/@webex/plugin-cc/package.json | jq '.scripts'

# Check if this is a new package
echo -e "\nChecking git history of the package..."
git log --diff-filter=A -- packages/@webex/plugin-cc/ | head -n 5

Length of output: 1311

packages/@webex/plugin-cc/src/WebSocket/config.ts (2)

1-47: 🛠️ Refactor suggestion

Add TypeScript interface for configuration

Consider adding a TypeScript interface to properly type the configuration object and improve maintainability.

interface WebSocketConfig {
  pingInterval: number;
  pongTimeout: number;
  backoffTimeMax: number;
  backoffTimeReset: number;
  forceCloseDelay: number;
  beforeLogoutOptionsCloseReason: string;
  authorizationRequired: boolean;
  acknowledgementRequired: boolean;
}

const webSocketConfig: WebSocketConfig = {
  // ... existing configuration
};

23-27: ⚠️ Potential issue

Fix incorrect JSDoc type annotation

The @type annotation for forceCloseDelay is incorrect.

- * @type {[type]}
+ * @type {number}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

   * Milliseconds to wait for a close frame before declaring the socket dead and
   * discarding it
   * @type {number}
   */
  forceCloseDelay: process.env.MERCURY_FORCE_CLOSE_DELAY || 2000,
packages/@webex/plugin-cc/README.md (3)

30-31: ⚠️ Potential issue

Remove template text from Building section

This appears to be template content that should be replaced with actual build instructions specific to the Contact Center plugin.


70-71: ⚠️ Potential issue

Fix heading level and URL formatting

  1. The heading level should be h2 to maintain consistency with other sections
  2. The URL should be properly formatted as a markdown link
-### Kitchen Sink App
-To test Contact Center SDK API, use this Kitchen Sink app: https://webex.github.io/webex-js-sdk/samples/contact-center/
+## Kitchen Sink App
+To test Contact Center SDK API, use this [Kitchen Sink app](https://webex.github.io/webex-js-sdk/samples/contact-center/).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

## Kitchen Sink App
To test Contact Center SDK API, use this [Kitchen Sink app](https://webex.github.io/webex-js-sdk/samples/contact-center/).
🧰 Tools
🪛 Markdownlint

70-70: Expected: h2; Actual: h3
Heading levels should only increment by one level at a time

(MD001, heading-increment)


71-71: null
Bare URL used

(MD034, no-bare-urls)


16-18: 💡 Codebase verification

⚠️ Potential issue

Based on the search results, I can now provide a final response:

Documentation links should reference existing Web Calling SDK documentation

The empty documentation links in the Contact Center plugin README should point to the existing Web Calling SDK documentation found in the packages/calling/README.md file:

Since the Contact Center plugin appears to be built on top of the Web Calling SDK functionality, these existing documentation resources would provide a good foundation for users getting started with the SDK.

🔗 Analysis chain

Documentation links need to be added before merging

The empty documentation links need to be populated with actual URLs to ensure users can access the introduction and quickstart guide.

Let's check if these docs exist elsewhere in the repository:


Let me try a different search strategy to find any documentation related to Web Calling SDK or Contact Center features.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential documentation files
fd -e md -e mdx . | grep -i "quickstart\|introduction"

Length of output: 56


Script:

#!/bin/bash
# Search for documentation or guides related to Web Calling or Contact Center
rg -i -g "*.{md,mdx}" "web calling|contact center|getting started" -A 2 -B 2

Length of output: 3071


Script:

#!/bin/bash
# Look for any docs directory or documentation files
fd -t d "docs?"

# List all markdown files in the repository for a broader view
fd -e md -e mdx .

Length of output: 4607


Script:

#!/bin/bash
# Check if there are any other README files that might contain these docs
fd "README" -e md

Length of output: 4142

🧰 Tools
🪛 Markdownlint

17-17: null
No empty links

(MD042, no-empty-links)


18-18: null
No empty links

(MD042, no-empty-links)

packages/@webex/plugin-cc/package.json (2)

25-32: 🛠️ Refactor suggestion

Reorganize dependencies and review versions.

  1. Move jest-html-reporters to devDependencies as it's only needed during development/testing.
  2. Consider using a more recent version of buffer (current latest is 6.0.3).
 "dependencies": {
   "@types/platform": "1.3.4",
   "@webex/calling": "workspace:*",
   "@webex/internal-plugin-mercury": "workspace:*",
   "@webex/webex-core": "workspace:*",
-  "buffer": "6.0.3",
-  "jest-html-reporters": "3.0.11"
+  "buffer": "6.0.3"
 },
 "devDependencies": {
+  "jest-html-reporters": "3.0.11",
   // ... other dev dependencies
 }

Committable suggestion was skipped due to low confidence.


14-24: 🛠️ Refactor suggestion

Add coverage-specific scripts to align with PR objectives.

To better support the coverage requirements:

 "scripts": {
   "build:src": "webex-legacy-tools build -dest \"./dist\" -src \"./src\" -js -ts && yarn build",
   "build": "yarn run -T tsc --declaration true --declarationDir ./dist/types",
   "docs": "typedoc --emit none",
   "fix:lint": "eslint 'src/**/*.ts' --fix",
   "fix:prettier": "prettier \"src/**/*.ts\" --write",
   "prebuild": "rimraf dist",
   "test": "yarn test:style && yarn test:unit",
   "test:style": "eslint 'src/**/*.ts'",
-  "test:unit": "webex-legacy-tools test --unit --runner jest"
+  "test:unit": "webex-legacy-tools test --unit --runner jest --coverage",
+  "test:coverage": "yarn test:unit --coverage",
+  "coverage:open": "open coverage/lcov-report/index.html"
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  "scripts": {
    "build:src": "webex-legacy-tools build -dest \"./dist\" -src \"./src\" -js -ts && yarn build",
    "build": "yarn run -T tsc --declaration true --declarationDir ./dist/types",
    "docs": "typedoc --emit none",
    "fix:lint": "eslint 'src/**/*.ts' --fix",
    "fix:prettier": "prettier \"src/**/*.ts\" --write",
    "prebuild": "rimraf dist",
    "test": "yarn test:style && yarn test:unit",
    "test:style": "eslint 'src/**/*.ts'",
    "test:unit": "webex-legacy-tools test --unit --runner jest --coverage",
    "test:coverage": "yarn test:unit --coverage",
    "coverage:open": "open coverage/lcov-report/index.html"
  },
docs/samples/contact-center/index.html (3)

6-6: ⚠️ Potential issue

Fix incorrect plugin name in title.

The title mentions "Meetings Plugin" but this is actually a Contact Center sample.

-  <title>Webex JavaScript SDK Sample: Meetings Plugin</title>
+  <title>Webex JavaScript SDK Sample: Contact Center Plugin</title>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  <title>Webex JavaScript SDK Sample: Contact Center Plugin</title>

95-99: ⚠️ Potential issue

Fix HTML structure in Agent Desktop section.

There are mismatched closing tags and an empty content section.

Fix the HTML structure:

      <div class="section-content">
-            </div>
-          </div>
-        </fieldset>
-      </div>
+        <!-- Add your Agent Desktop content here -->
+      </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      <div class="section-content">
        <!-- Add your Agent Desktop content here -->
      </div>

54-64: ⚠️ Potential issue

Improve security for access token handling.

The access token input field needs security improvements:

  1. The token is visible in plain text
  2. There's no validation for empty tokens

Apply these security enhancements:

-              <input id="access-token" name="accessToken" placeholder="Access Token" value="" type="text">
+              <input id="access-token" name="accessToken" placeholder="Access Token" value="" type="password" required 
+                     autocomplete="off" pattern=".{10,}" title="Please enter a valid access token">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

          <form id="credentials">
            <p class="note">
              NOTE: Click <a href="https://developer.webex.com/docs/getting-started" target="_blank">here</a> for
              access token
            </p>
            <div>
              <input id="access-token" name="accessToken" placeholder="Access Token" value="" type="password" required 
                     autocomplete="off" pattern=".{10,}" title="Please enter a valid access token">
              <button id="access-token-save" class="btn-code" type="submit">webex.init()</button>
              <p id="access-token-status" class="status-par">Not initialized</p>
            </div>
          </form>
docs/samples/contact-center/app.js (7)

1-18: 🛠️ Refactor suggestion

Consider reducing ESLint suppressions and adding type definitions.

The code starts with multiple ESLint suppressions that could hide potential issues:

  • no-unused-vars: Could mask dead code
  • no-console: Console statements should be replaced with proper logging
  • no-global-assign: Could lead to unexpected behavior

Additionally, the global variables would benefit from type definitions.

Consider:

  1. Removing unnecessary ESLint suppressions
  2. Adding JSDoc type definitions for globals:
/** @type {import('@webex/webex-core').default} */
let webex;
/** @type {string} */
let agentDeviceType;
/** @type {string} */
let deviceId;

106-112: ⚠️ Potential issue

Enhance registration error handling and UI feedback.

The current registration implementation lacks detailed error handling and user feedback.

Consider this improved implementation:

 function register() {
+    const registerStatus = document.querySelector('#register-status');
+    registerBtn.disabled = true;
+    registerStatus.innerText = 'Registering...';
+
     webex.cc.register().then((data) => {
-        console.log('Event subscription successful: ', data);
+        registerStatus.innerText = 'Registration successful!';
+        console.log('Registration successful:', data);
     }).catch((error) => {
-        console.log('Event subscription failed');
+        registerStatus.innerText = `Registration failed: ${error.message}`;
+        console.error('Registration error:', error);
+        registerBtn.disabled = false;
     })
 }

Committable suggestion was skipped due to low confidence.


27-38: ⚠️ Potential issue

Security: Improve token storage implementation.

The current token storage implementation has several security considerations:

  1. Storing sensitive tokens in localStorage without encryption
  2. Direct time comparison for expiration could be affected by system clock changes
  3. No error handling for localStorage operations

Consider implementing these improvements:

+ const TWELVE_HOURS_MS = 12 * 60 * 60 * 1000;
+ 
+ function isTokenExpired() {
+   try {
+     const expiryTime = parseInt(localStorage.getItem('date'), 10);
+     return !expiryTime || expiryTime <= new Date().getTime();
+   } catch (error) {
+     console.error('Error checking token expiration:', error);
+     return true;
+   }
+ }
+ 
+ function storeToken(token) {
+   try {
+     // Consider encrypting token before storage
+     localStorage.setItem('access-token', token);
+     localStorage.setItem('date', String(new Date().getTime() + TWELVE_HOURS_MS));
+   } catch (error) {
+     console.error('Error storing token:', error);
+   }
+ }

Committable suggestion was skipped due to low confidence.


148-169: 🛠️ Refactor suggestion

Refactor collapse/expand functions to reduce duplication.

The current implementation has duplicated logic between collapse and expand functions.

Consider this more maintainable implementation:

-function collapseAll() {
-  allSectionContentElements.forEach((el) => {
-    el.classList.add('collapsed');
-  });
-
-  allArrowElements.forEach((el) => {
-    el.classList.replace('fa-angle-down', 'fa-angle-up');
-  });
-}
-
-function expandAll() {
-  allSectionContentElements.forEach((el) => {
-    el.classList.remove('collapsed');
-  });
-
-  allArrowElements.forEach((el) => {
-    el.classList.replace('fa-angle-up', 'fa-angle-down');
-  });
-}
+function toggleAllSections(shouldCollapse) {
+  allSectionContentElements.forEach((el) => {
+    el.classList.toggle('collapsed', shouldCollapse);
+  });
+
+  allArrowElements.forEach((el) => {
+    const [fromClass, toClass] = shouldCollapse 
+      ? ['fa-angle-down', 'fa-angle-up']
+      : ['fa-angle-up', 'fa-angle-down'];
+    if (el.classList.contains(fromClass)) {
+      el.classList.replace(fromClass, toClass);
+    }
+  });
+}
+
+const collapseAll = () => toggleAllSections(true);
+const expandAll = () => toggleAllSections(false);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const allSectionContentElements = document.querySelectorAll('.section-content');
const allArrowElements = document.querySelectorAll('.arrow');

function toggleAllSections(shouldCollapse) {
  allSectionContentElements.forEach((el) => {
    el.classList.toggle('collapsed', shouldCollapse);
  });

  allArrowElements.forEach((el) => {
    const [fromClass, toClass] = shouldCollapse 
      ? ['fa-angle-down', 'fa-angle-up']
      : ['fa-angle-up', 'fa-angle-down'];
    if (el.classList.contains(fromClass)) {
      el.classList.replace(fromClass, toClass);
    }
  });
}

const collapseAll = () => toggleAllSections(true);
const expandAll = () => toggleAllSections(false);

133-146: ⚠️ Potential issue

Security: Improve URL token handling.

The current implementation has several security and implementation concerns:

  1. Tokens in URL are visible in browser history
  2. No validation of token format
  3. Unsafe parseInt usage
  4. Comment acknowledges "hacky" implementation

Consider this safer implementation:

+ function validateToken(token) {
+   // Add your token format validation logic
+   return token && typeof token === 'string' && token.length > 0;
+ }
+ 
 if (window.location.hash) {
-  // hacky way to get access token from hash
-  const urlParams = new URLSearchParams(window.location.hash.replace('#', '?'));
+  try {
+    const hashParams = new URLSearchParams(window.location.hash.slice(1));
+    const accessToken = hashParams.get('access_token');
+    const expiresIn = hashParams.get('expires_in');
 
-  const accessToken = urlParams.get('access_token');
-  const expiresIn = urlParams.get('expires_in');
-
-  if (accessToken) {
-    localStorage.setItem('access-token', accessToken);
-    localStorage.setItem('date', new Date().getTime() + parseInt(expiresIn, 10));
-    tokenElm.value = accessToken;
+    if (validateToken(accessToken)) {
+      const expiryMs = Number(expiresIn) * 1000;
+      if (!Number.isNaN(expiryMs)) {
+        localStorage.setItem('access-token', accessToken);
+        localStorage.setItem('date', String(new Date().getTime() + expiryMs));
+        tokenElm.value = accessToken;
+        // Clear hash to remove token from URL
+        window.history.replaceState(null, '', window.location.pathname);
+      }
+    }
+  } catch (error) {
+    console.error('Error processing URL token:', error);
   }
 }

Committable suggestion was skipped due to low confidence.


114-131: 🛠️ Refactor suggestion

Refactor collapsible section implementation.

The current implementation has several issues:

  1. Hard-coded index for section reference is fragile
  2. Complex class toggling logic
  3. Long ternary expression reduces readability

Consider this improved implementation:

+ const AUTH_SECTION_ID = 'auth-registration-section';
+ 
+ function toggleArrowIcon(arrowIcon, isExpanded) {
+   const newClass = isExpanded ? 'fa-angle-down' : 'fa-angle-up';
+   const oldClass = isExpanded ? 'fa-angle-up' : 'fa-angle-down';
+   arrowIcon.classList.replace(oldClass, newClass);
+ }
+ 
 allCollapsibleElements.forEach((el) => {
   el.addEventListener('click', (event) => {
     const {parentElement} = event.currentTarget;
     const sectionContentElement = parentElement.querySelector('.section-content');
     const arrowIcon = parentElement.querySelector('.arrow');
+    const isExpanded = !sectionContentElement.classList.contains('collapsed');
 
     sectionContentElement.classList.toggle('collapsed');
-    arrowIcon.classList.contains('fa-angle-down') ? arrowIcon.classList.replace('fa-angle-down', 'fa-angle-up') : arrowIcon.classList.replace('fa-angle-up', 'fa-angle-down');
+    toggleArrowIcon(arrowIcon, isExpanded);
 
-    if(el.innerText !== 'Auth & Registration' && !sectionContentElement.classList.contains('collapsed')) {
-      // Note: Index of the Auth & Registration section may change if further re-ordering is done
-      allCollapsibleElements[1].parentElement.querySelector('.section-content').classList.add('collapsed');
-      allCollapsibleElements[1].parentElement.querySelector('.arrow').classList.replace('fa-angle-down', 'fa-angle-up');
+    if (parentElement.id !== AUTH_SECTION_ID && isExpanded) {
+      const authSection = document.getElementById(AUTH_SECTION_ID);
+      if (authSection) {
+        const authContent = authSection.querySelector('.section-content');
+        const authArrow = authSection.querySelector('.arrow');
+        authContent.classList.add('collapsed');
+        toggleArrowIcon(authArrow, false);
+      }
     }
   });
 });

Committable suggestion was skipped due to low confidence.


76-102: ⚠️ Potential issue

Add error handling for Webex initialization.

The current implementation lacks error handling and exposes the Webex instance globally.

Consider these improvements:

 function initWebex(e) {
   e.preventDefault();
-  console.log('Authentication#initWebex()');
+  try {
+    tokenElm.disabled = true;
+    saveElm.disabled = true;
+    authStatusElm.innerText = 'initializing...';
 
-  tokenElm.disabled = true;
-  saveElm.disabled = true;
-  authStatusElm.innerText = 'initializing...';
+    const webexConfig = generateWebexConfig({});
+    webex = Webex.init({
+      config: webexConfig,
+      credentials: {
+        access_token: tokenElm.value
+      }
+    });
 
-  const webexConfig = generateWebexConfig({})
-
-  webex = window.webex = Webex.init({
-    config: webexConfig,
-    credentials: {
-      access_token: tokenElm.value
-    }
-  });
-
-  webex.once('ready', async () => {
-    console.log('Authentication#initWebex() :: Webex Ready');
-
-    authStatusElm.innerText = 'Saved access token!';
-
-    registerBtn.disabled = false;
-  });
+    webex.once('ready', () => {
+      authStatusElm.innerText = 'Saved access token!';
+      registerBtn.disabled = false;
+    });
 
+    webex.on('error', (error) => {
+      authStatusElm.innerText = 'Initialization failed!';
+      console.error('Webex initialization error:', error);
+    });
+  } catch (error) {
+    authStatusElm.innerText = 'Initialization failed!';
+    console.error('Error initializing Webex:', error);
+    tokenElm.disabled = false;
+    saveElm.disabled = false;
+  }
   return false;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

function initWebex(e) {
  e.preventDefault();
  try {
    tokenElm.disabled = true;
    saveElm.disabled = true;
    authStatusElm.innerText = 'initializing...';

    const webexConfig = generateWebexConfig({});
    webex = Webex.init({
      config: webexConfig,
      credentials: {
        access_token: tokenElm.value
      }
    });

    webex.once('ready', () => {
      authStatusElm.innerText = 'Saved access token!';
      registerBtn.disabled = false;
    });

    webex.on('error', (error) => {
      authStatusElm.innerText = 'Initialization failed!';
      console.error('Webex initialization error:', error);
    });
  } catch (error) {
    authStatusElm.innerText = 'Initialization failed!';
    console.error('Error initializing Webex:', error);
    tokenElm.disabled = false;
    saveElm.disabled = false;
  }
  return false;
}
packages/@webex/plugin-cc/test/unit/spec/WebSocket.ts (1)

173-193: 🛠️ Refactor suggestion

Consider splitting event listener tests and adding edge cases.

While the current test is good, consider:

  1. Splitting into separate test cases for on and off
  2. Adding tests for edge cases:
    • Multiple listeners for the same event
    • Invalid event types
    • Removing non-existent listeners
docs/samples/contact-center/style.css (4)

261-298: 🛠️ Refactor suggestion

Reconsider use of !important in utility classes.

While !important in utility classes is a common pattern, consider:

  1. Using a more specific selector instead
  2. Adding more comprehensive spacing utilities
 .u-m {
-    margin: 1rem !important;
+    margin: var(--spacing-base);
 }
 
+/* Add more granular spacing utilities */
+.u-m-sm {
+    margin: var(--spacing-sm);
+}
+
+.u-m-lg {
+    margin: var(--spacing-lg);
+}

Committable suggestion was skipped due to low confidence.


414-424: 🛠️ Refactor suggestion

Optimize rendering performance.

Consider the following performance optimizations:

  1. Use will-change for animated elements
  2. Optimize box-shadow rendering
 .global-toggle-btn {
     width: 10rem;
     display: flex;
     align-items: center;
     justify-content: center;
     padding: 0.25rem;
     background-color: white;
     color: #0052bf;
     border: #0052bf 1px solid;
-    box-shadow: 3px 3px 4px 1px rgb(0 0 0 / 40%);
+    /* Optimize box-shadow */
+    box-shadow: 0 2px 4px rgb(0 0 0 / 20%);
+    /* Add will-change for smooth animations */
+    will-change: transform, box-shadow;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  .global-toggle-btn {
    width: 10rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem;
    background-color: white;
    color: #0052bf;
    border: #0052bf 1px solid;
    /* Optimize box-shadow */
    box-shadow: 0 2px 4px rgb(0 0 0 / 20%);
    /* Add will-change for smooth animations */
    will-change: transform, box-shadow;
  }

80-90: 🛠️ Refactor suggestion

Enhance accessibility and animations for collapsible sections.

The current implementation could benefit from:

  1. ARIA attributes for better screen reader support
  2. Smooth height transitions
 .collapsible {
     cursor: pointer;
+    /* Add ARIA support */
+    role: button;
+    aria-expanded: true;
 }
 
 .section-content {
     height: auto;
+    transition: height 0.3s ease-in-out;
 }
 
 .collapsed {
     height: 0;
+    overflow: hidden;
 }

Committable suggestion was skipped due to low confidence.


154-190: 🛠️ Refactor suggestion

Improve z-index management and speaking indicator.

Consider the following improvements:

  1. Use CSS variables for z-index values
  2. Add animation to the speaking indicator
+:root {
+    --z-index-base: 0;
+    --z-index-overlay: 1;
+    --z-index-label: 2;
+}

 .multistream-remote-video {
-    z-index: 0;
+    z-index: var(--z-index-base);
 }
 .video-label {
-    z-index: 2;
+    z-index: var(--z-index-label);
 }
 
 .video-overlay {
-    z-index: 1;
+    z-index: var(--z-index-overlay);
 }

 .speaking {
     background-color: rgba(94, 217, 248, 0.5);
+    transition: background-color 0.3s ease-in-out;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  :root {
      --z-index-base: 0;
      --z-index-overlay: 1;
      --z-index-label: 2;
  }

  .multistream-remote-video {
    z-index: var(--z-index-base);
  }
  .video-label {
    z-index: var(--z-index-label);
    position: absolute;
    bottom: 0px;
    left: 0px;
    width: 100%;
    text-align: center;
    color: black;
    background-color: rgba(255,255,255,0.5);
  }
  
  .video-overlay {
    z-index: var(--z-index-overlay);
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    align-content: center;
    border-radius: 0.5rem;
    background-color: lightgray;
  }
  
  .video-overlay-text {
    color: black;
    width: 100%;
    text-align: center;
  }
  
  .speaking {
    background-color: rgba(94, 217, 248, 0.5);
    transition: background-color 0.3s ease-in-out;
  }
packages/@webex/plugin-cc/test/unit/spec/cc.ts (1)

232-249: ⚠️ Potential issue

Improve reliability of timeout test.

The current timeout test could be flaky as it relies on real timers and actual timeouts. Consider refactoring to use Jest's fake timers consistently:

-  it('should reject the promise if the event times out', (done) => {
-    const resolveMock = jest.fn();
-    const rejectMock = jest.fn().mockImplementation((error) => {
-      expect(error.message).toBe('Time out waiting for event: register');
-      done();
-    });
-
-    webex.cc.addEventHandler('register', resolveMock, rejectMock);
-
-    const eventHandler = webex.cc.eventHandlers.get('register');
-    expect(eventHandler).toBeDefined();
-
-    // Simulate timeout
-    setTimeout(() => {
-      expect(rejectMock).toHaveBeenCalled();
-    }, WEBSOCKET_EVENT_TIMEOUT + 100);
-  }, WEBSOCKET_EVENT_TIMEOUT + 200);
+  it('should reject the promise if the event times out', () => {
+    jest.useFakeTimers();
+    
+    const resolveMock = jest.fn();
+    const rejectMock = jest.fn();
+    
+    webex.cc.addEventHandler('register', resolveMock, rejectMock);
+    
+    const eventHandler = webex.cc.eventHandlers.get('register');
+    expect(eventHandler).toBeDefined();
+    
+    jest.advanceTimersByTime(WEBSOCKET_EVENT_TIMEOUT + 1);
+    
+    expect(rejectMock).toHaveBeenCalledWith(
+      expect.objectContaining({
+        message: 'Time out waiting for event: register'
+      })
+    );
+    
+    jest.useRealTimers();
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    it('should reject the promise if the event times out', () => {
      jest.useFakeTimers();
      
      const resolveMock = jest.fn();
      const rejectMock = jest.fn();
      
      webex.cc.addEventHandler('register', resolveMock, rejectMock);
      
      const eventHandler = webex.cc.eventHandlers.get('register');
      expect(eventHandler).toBeDefined();
      
      jest.advanceTimersByTime(WEBSOCKET_EVENT_TIMEOUT + 1);
      
      expect(rejectMock).toHaveBeenCalledWith(
        expect.objectContaining({
          message: 'Time out waiting for event: register'
        })
      );
      
      jest.useRealTimers();
    });
packages/@webex/webex-core/test/unit/spec/services/service-catalog.js (1)

281-310: 🛠️ Refactor suggestion

Consider using test.each for protocol variations.

While the tests are comprehensive, they could be more maintainable using Jest's test.each to test different protocol combinations:

const protocols = [
  ['https', 'https://signin.example.com'],
  ['wss', 'https://signin.example.com'],
  ['http', 'https://signin.example.com'],
];

it.each(protocols)(
  'should handle %s protocol correctly',
  (protocol, expectedUrl) => {
    catalog.serviceGroups = {
      signin: [{defaultUrl: expectedUrl, hosts: []}],
    };
    const result = catalog.findServiceUrlFromUrl(`${protocol}://signin.example.com/resource`);
    assert.deepEqual(result, {defaultUrl: expectedUrl, hosts: []});
  }
);
packages/@webex/internal-plugin-mercury/src/socket/socket-base.js (2)

331-337: 🛠️ Refactor suggestion

Improve message handling robustness and performance.

A few suggestions for the message handling changes:

  1. Add validation for the ping message type
  2. Optimize the pong event emission
 if (this.acknowledgementRequired) {
   this._acknowledge(processedEvent);
 }
-if (data.type === 'pong' || data.type === 'ping') {
+// Validate message type for ping/pong handling
+const isPingOrPong = data.type === 'pong' || 
+  (data.type === 'ping' && typeof data.id === 'string');
+
+if (isPingOrPong) {
   // added above ping condition to handle pong messages of contact center where type is 'ping' instead of 'pong'
-  this.emit('pong', {...processedEvent, type: 'pong'});
+  this.emit('pong', processedEvent);
} else {

Committable suggestion was skipped due to low confidence.


266-277: ⚠️ Potential issue

Improve robustness of authorization bypass flow.

The current implementation has potential issues:

  1. The socket.onclose handler isn't set when bypassing authorization
  2. Missing error handling in the non-authorization path
 if (this.authorizationRequired) {
   this._authorize()
     .then(() => {
       this.logger.info(`socket,${this._domain}: authorized`);
       socket.onclose = this.onclose;
       resolve();
     })
     .catch(reject);
 } else {
+  this.logger.info(`socket,${this._domain}: skipping authorization`);
+  socket.onclose = this.onclose;
   this._ping();
+  resolve();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        // Added the "authorizationRequired" condition to bypass the "_authorize" in case of the contact center context, in which case it is configured as false.
        if (this.authorizationRequired) {
          this._authorize()
            .then(() => {
              this.logger.info(`socket,${this._domain}: authorized`);
              socket.onclose = this.onclose;
              resolve();
            })
            .catch(reject);
        } else {
          this.logger.info(`socket,${this._domain}: skipping authorization`);
          socket.onclose = this.onclose;
          this._ping();
          resolve();
        }
packages/@webex/internal-plugin-mercury/src/mercury.js (1)

519-527: ⚠️ Potential issue

Fix duplicate event emission and indentation.

There are two issues in the event emission logic:

  1. The namespace event is emitted twice when there's a fully qualified event type
  2. The indentation is inconsistent

Apply this diff to fix the issues:

        if (data.eventType) {
          const [namespace] = data.eventType.split('.');

-          if (namespace === data.eventType) {
-            this._emit(`event:${namespace}`, envelope);
-          } else {
-            this._emit(`event:${namespace}`, envelope);
-            this._emit(`event:${data.eventType}`, envelope);
-          }
+          this._emit(`event:${namespace}`, envelope);
+          if (namespace !== data.eventType) {
+            this._emit(`event:${data.eventType}`, envelope);
+          }
        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        if (data.eventType) {
          const [namespace] = data.eventType.split('.');

          this._emit(`event:${namespace}`, envelope);
          if (namespace !== data.eventType) {
            this._emit(`event:${data.eventType}`, envelope);
          }
        }
packages/@webex/internal-plugin-mercury/test/unit/spec/socket.js (2)

203-243: 🛠️ Refactor suggestion

Add test cases for error scenarios.

The test suite is missing error scenarios for the new authorization and acknowledgment options. Consider adding test cases for:

  1. Network errors during authorization
  2. Invalid authorization responses
  3. Timeout scenarios

Would you like me to provide example test cases for these scenarios?


203-243: ⚠️ Potential issue

Fix syntax errors in test cases and improve assertions.

The test cases for authorizationRequired option contain syntax errors (missing function body wrapping) and could benefit from better assertions.

-it('accepts authorizationRequired option as false and skip authorize', () => {
+it('accepts authorizationRequired option as false and skips authorize', () => {
   const s = new Socket();
   const authorizeSpy = sinon.spy(socket, '_authorize');
-  socket.open('ws://example.com', {
+  return socket.open('ws://example.com', {
     forceCloseDelay: mockoptions.forceCloseDelay,
     pingInterval: mockoptions.pingInterval,
     pongTimeout: mockoptions.pongTimeout,
     logger: console,
     token: 'mocktoken',
     trackingId: 'mocktrackingid',
     logLevelToken: 'mocklogleveltoken',
     authorizationRequired: false,
-  });
+  }).then(() => {
+    mockWebSocket.readyState = 1;
+    mockWebSocket.emit('open');

+    assert.notCalled(authorizeSpy);
+    assert.called(socket._ping);
+  });
 });

-it('accepts authorizationRequired option as true and calles authorize', () => {
+it('accepts authorizationRequired option as true and calls authorize', () => {
   const s = new Socket();
   const authorizeSpy = sinon.spy(socket, '_authorize');
-  socket.open('ws://example.com', {
+  return socket.open('ws://example.com', {
     forceCloseDelay: mockoptions.forceCloseDelay,
     pingInterval: mockoptions.pingInterval,
     pongTimeout: mockoptions.pongTimeout,
     logger: console,
     token: 'mocktoken',
     trackingId: 'mocktrackingid',
     logLevelToken: 'mocklogleveltoken',
     authorizationRequired: true,
-  });
+  }).then(() => {
+    mockWebSocket.readyState = 1;
+    mockWebSocket.emit('open');

+    assert.called(authorizeSpy);
+    assert.called(socket._ping);
+  });
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      it('accepts authorizationRequired option as false and skips authorize', () => {
        const s = new Socket();
        const authorizeSpy = sinon.spy(socket, '_authorize');
        return socket.open('ws://example.com', {
          forceCloseDelay: mockoptions.forceCloseDelay,
          pingInterval: mockoptions.pingInterval,
          pongTimeout: mockoptions.pongTimeout,
          logger: console,
          token: 'mocktoken',
          trackingId: 'mocktrackingid',
          logLevelToken: 'mocklogleveltoken',
          authorizationRequired: false,
        }).then(() => {
          mockWebSocket.readyState = 1;
          mockWebSocket.emit('open');

          assert.notCalled(authorizeSpy);
          assert.called(socket._ping);
        });
      });

      it('accepts authorizationRequired option as true and calls authorize', () => {
        const s = new Socket();
        const authorizeSpy = sinon.spy(socket, '_authorize');
        return socket.open('ws://example.com', {
          forceCloseDelay: mockoptions.forceCloseDelay,
          pingInterval: mockoptions.pingInterval,
          pongTimeout: mockoptions.pongTimeout,
          logger: console,
          token: 'mocktoken',
          trackingId: 'mocktrackingid',
          logLevelToken: 'mocklogleveltoken',
          authorizationRequired: true,
        }).then(() => {
          mockWebSocket.readyState = 1;
          mockWebSocket.emit('open');

          assert.called(authorizeSpy);
          assert.called(socket._ping);
        });
      });
packages/@webex/internal-plugin-mercury/test/unit/spec/mercury.js (1)

716-730: 🛠️ Refactor suggestion

Consider expanding test coverage for edge cases.

The new test case for handling messages without eventType is good. Consider adding more edge cases to create a comprehensive suite:

+      it('handles message with null eventType', () => {
+        sinon.spy(mercury, '_getEventHandlers');
+        sinon.spy(mercury, '_emit');
+        const event = {data: {data: {eventType: null, mydata: 'some data'}}};
+        return Promise.resolve(mercury._onmessage(event)).then(() => {
+          assert.calledWith(mercury._getEventHandlers, null);
+          assert.calledWith(mercury._emit, 'event', event.data);
+          mercury._emit.restore();
+          mercury._getEventHandlers.restore();
+        });
+      });
+
+      it('handles message with missing data property', () => {
+        sinon.spy(mercury, '_getEventHandlers');
+        sinon.spy(mercury, '_emit');
+        const event = {data: {}};
+        return Promise.resolve(mercury._onmessage(event)).then(() => {
+          assert.calledWith(mercury._getEventHandlers, undefined);
+          assert.calledWith(mercury._emit, 'event', event.data);
+          mercury._emit.restore();
+          mercury._getEventHandlers.restore();
+        });
+      });

Committable suggestion was skipped due to low confidence.

packages/@webex/plugin-cc/src/WebSocket/WebSocket.ts (5)

33-35: ⚠️ Potential issue

Avoid directly invoking prototype methods in the constructor.

Directly calling Mercury.prototype.initialize is unconventional and may lead to unexpected behavior. The super() call should handle necessary initialization from the parent class.

Consider removing the direct prototype method call:

constructor(options = {}) {
  super(options);
- Mercury.prototype.initialize(this, options);
}

If additional initialization is required, consider overriding lifecycle methods or properly extending the base class.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  constructor(options = {}) {
    super(options);
}

130-136: 🛠️ Refactor suggestion

Refactor 'disconnectWebSocket' to use 'async/await' for consistency.

Using async/await here aligns with modern practices and improves code clarity.

Refactored method:

- disconnectWebSocket(): Promise<void> {
-   return this.disconnect().then(() => {
-     this.datachannelUrl = undefined;
-     this.subscriptionId = undefined;
-     this.webSocketUrl = undefined;
-   });
- }
+ async disconnectWebSocket(): Promise<void> {
+   await this.disconnect();
+   this.datachannelUrl = undefined;
+   this.subscriptionId = undefined;
+   this.webSocketUrl = undefined;
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  async disconnectWebSocket(): Promise<void> {
    await this.disconnect();
    this.datachannelUrl = undefined;
    this.subscriptionId = undefined;
    this.webSocketUrl = undefined;
  }

6-6: ⚠️ Potential issue

Avoid using 'any' in class extension.

Casting Mercury to any disables TypeScript's type checking and defeats the purpose of using types. Consider resolving type incompatibilities properly without resorting to any.

Consider updating the class declaration:

- class WebSocket extends (Mercury as any) implements IWebSocket {
+ class WebSocket extends Mercury implements IWebSocket {

If type incompatibilities exist, you may need to adjust the types or interfaces of Mercury or IWebSocket to ensure compatibility.

Committable suggestion was skipped due to low confidence.


89-99: 🛠️ Refactor suggestion

Refactor 'subscribeAndConnect' to use 'async/await' and remove unnecessary error handling.

Adopting async/await improves readability, and removing redundant catch blocks streamlines the code.

Refactored subscribeAndConnect method:

- subscribeAndConnect({ datachannelUrl, body }: { datachannelUrl: string; body: SubscribeRequest; }): Promise<void> {
-   return this.subscribeNotifications({ datachannelUrl, body })
-     .then(() => {
-       this.datachannelUrl = datachannelUrl;
-       this.connect(this.webSocketUrl);
-     });
- }
+ async subscribeAndConnect({ datachannelUrl, body }: { datachannelUrl: string; body: SubscribeRequest; }): Promise<void> {
+   await this.subscribeNotifications({ datachannelUrl, body });
+   this.datachannelUrl = datachannelUrl;
+   this.connect(this.webSocketUrl);
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    async subscribeAndConnect({ datachannelUrl, body }: { datachannelUrl: string; body: SubscribeRequest; }): Promise<void> {
      await this.subscribeNotifications({ datachannelUrl, body });
      this.datachannelUrl = datachannelUrl;
      this.connect(this.webSocketUrl);
    }

70-72: 🛠️ Refactor suggestion

Refactor to use 'async/await' for better readability.

Using async/await can enhance the clarity of asynchronous operations and reduce complexity.

Refactored subscribeNotifications method:

- subscribeNotifications({ datachannelUrl, body }: { datachannelUrl: string; body: SubscribeRequest; }): Promise<void> {
-   return this.request({
-     method: HTTP_METHODS.POST,
-     url: datachannelUrl,
-     body,
-   })
-     .then((res) => {
-       this.webSocketUrl = res.body.webSocketUrl;
-       this.subscriptionId = res.body.subscriptionId;
-     });
- }
+ async subscribeNotifications({ datachannelUrl, body }: { datachannelUrl: string; body: SubscribeRequest; }): Promise<void> {
+   const res = await this.request({
+     method: HTTP_METHODS.POST,
+     url: datachannelUrl,
+     body,
+   });
+   this.webSocketUrl = res.body.webSocketUrl;
+   this.subscriptionId = res.body.subscriptionId;
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      async subscribeNotifications({ datachannelUrl, body }: { datachannelUrl: string; body: SubscribeRequest; }): Promise<void> {
        const res = await this.request({
          method: HTTP_METHODS.POST,
          url: datachannelUrl,
          body,
        });
        this.webSocketUrl = res.body.webSocketUrl;
        this.subscriptionId = res.body.subscriptionId;
      }
packages/@webex/plugin-cc/src/types.ts (10)

159-159: ⚠️ Potential issue

Clarify and resolve the TODO comment

The TODO comment on line 159 contains grammatical errors and lacks clarity. Please update the comment to clearly describe the intended action and ensure that the EventResult type is correctly defined when the related PR is merged.


116-120: ⚠️ Potential issue

Reconsider exposing '$config' and '$webex' in 'IContactCenter' interface

The properties $config and $webex are marked with @ignore but are included in the public IContactCenter interface. If these properties are intended to be internal, consider removing them from the public interface or marking them as private to prevent unintended access.


77-77: 🛠️ Refactor suggestion

Specify a more precise type for 'presence' property

The presence property is currently typed as unknown. Providing a more specific type will improve type safety and code clarity.


94-94: 🛠️ Refactor suggestion

Provide a specific type for 'data' in 'submitClientMetrics'

The data parameter in submitClientMetrics is typed as unknown. Specifying a more precise type will enhance type safety and help prevent runtime errors.


53-53: 🛠️ Refactor suggestion

Ensure consistent interface naming conventions

Interfaces such as WebexSDK, IContactCenter, and WebSocketEvent have inconsistent naming conventions regarding the I prefix. Consider adopting a consistent naming strategy for interfaces to improve code readability and maintainability.

Also applies to: 112-112, 145-145


61-61: ⚠️ Potential issue

Correct 'callBack' to 'callback' in 'once' method for consistency

The parameter name callBack should be renamed to callback to follow standard camelCase naming conventions in JavaScript and TypeScript.

Apply this diff to fix the parameter name:

- once: (event: string, callBack: () => void) => void;
+ once: (event: string, callback: () => void) => void;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  once: (event: string, callback: () => void) => void;

40-46: ⚠️ Potential issue

Avoid duplication of 'clientType' in 'CCPluginConfig'

The clientType property appears both at the top level of CCPluginConfig and within the metrics object. This duplication could lead to inconsistencies. Consider removing one instance or ensuring they are consistently updated.

Apply this diff to remove the duplicate:

 export interface CCPluginConfig {
   allowMultiLogin: boolean;
-  clientType: string;
   isKeepAliveEnabled: boolean;
   force: boolean;
   metrics: {
     clientName: string;
     clientType: string;
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  isKeepAliveEnabled: boolean;
  force: boolean;
  metrics: {
    clientName: string;
    clientType: string;
  };

91-91: ⚠️ Potential issue

Handle cases where the service may not be found in 'get' method

The get method returns a string, but if the requested service is not found, it might return undefined. Consider updating the return type to string | undefined to handle such cases safely.

Apply this diff to update the return type:

- get(name: string, priorityHost?: boolean, serviceGroup?: string): string;
+ get(name: string, priorityHost?: boolean, serviceGroup?: string): string | undefined;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      get(name: string, priorityHost?: boolean, serviceGroup?: string): string | undefined;

15-25: ⚠️ Potential issue

Review inclusion of 'statusCode' in 'WebexRequestPayload'

The statusCode property in WebexRequestPayload is typically associated with responses rather than requests. Including it in the request payload may cause confusion. Consider removing it or clarifying its intended use.

Apply this diff to remove statusCode:

 type WebexRequestPayload = {
   method?: HTTP_METHODS;
   uri?: string;
   addAuthHeader?: boolean;
   headers?: {
     [key: string]: string | null;
   };
   body?: object;
-  statusCode?: number;
   json?: boolean;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

type WebexRequestPayload = {
  method?: HTTP_METHODS;
  uri?: string;
  addAuthHeader?: boolean;
  headers?: {
    [key: string]: string | null;
  };
  body?: object;
  json?: boolean;
};

145-150: 🛠️ Refactor suggestion

Design 'WebSocketEvent' to accommodate various event data

Currently, the WebSocketEvent interface has a fixed data structure with only agentId. If different events carry different data payloads, consider making data more flexible or using generics to handle various event types.

Apply this diff to make data generic:

-export interface WebSocketEvent {
+export interface WebSocketEvent<T = unknown> {
   type: CC_EVENTS;
   data: T;
 }

This change allows data to be of any type, accommodating different event payloads.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export interface WebSocketEvent<T = unknown> {
  type: CC_EVENTS;
  data: T;
}
packages/@webex/plugin-cc/src/cc.ts (5)

28-28: ⚠️ Potential issue

Replace any types with specific types for better type safety

Using any reduces type safety. Consider replacing data: any and error: any with more specific types to leverage TypeScript's strengths.


34-35: ⚠️ Potential issue

Avoid using @ts-ignore; address the underlying type issues

Using @ts-ignore suppresses TypeScript errors, potentially hiding real issues. Consider properly typing this.webex to eliminate the need for @ts-ignore.


38-39: ⚠️ Potential issue

Avoid using @ts-ignore; address the underlying type issues

Suppressing TypeScript errors with @ts-ignore can mask underlying problems. Ensure this.config is correctly typed to avoid the need for @ts-ignore.


72-77: 🛠️ Refactor suggestion

Consider using async/await syntax for consistency and error handling

To maintain consistency with the register method and improve readability, refactor unregister to use async/await and handle potential errors.

Apply this diff to refactor the method:

-public unregister(): Promise<void> {
-  return this.webSocket.disconnectWebSocket().then(() => {
-    this.webSocket.off(EVENT, this.processEvent);
-    this.registered = false;
-  });
+public async unregister(): Promise<void> {
+  try {
+    await this.webSocket.disconnectWebSocket();
+    this.webSocket.off(EVENT, this.processEvent);
+    this.registered = false;
+  } catch (error) {
+    this.$webex.logger.error(`Error disconnecting WebSocket: ${error}`);
+    throw error;
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  public async unregister(): Promise<void> {
    try {
      await this.webSocket.disconnectWebSocket();
      this.webSocket.off(EVENT, this.processEvent);
      this.registered = false;
    } catch (error) {
      this.$webex.logger.error(`Error disconnecting WebSocket: ${error}`);
      throw error;
    }
  }

94-114: 🛠️ Refactor suggestion

Refactor establishConnection to return a Promise for cleaner error handling

Passing the reject function to establishConnection increases coupling. Refactor establishConnection to return a Promise and use async/await for better error handling.

Here's how you might refactor:

  1. Modify establishConnection to return a Promise<void>:

    -private async establishConnection(reject: (error: Error) => void) {
    +private async establishConnection(): Promise<void> {
  2. Update the register method to handle the promise:

    public async register(): Promise<string> {
      this.wccApiUrl = this.$webex.internal.services.get(WCC_API_GATEWAY);
    
      this.listenForWebSocketEvents();
    
    - return new Promise((resolve, reject) => {
    -   this.addEventHandler(
    -     REGISTER_EVENT,
    -     (result) => {
    -       this.registered = true;
    -       resolve(result);
    -     },
    -     reject
    -   );
    -   this.establishConnection(reject);
    - });
    + try {
    +   await this.establishConnection();
    +   return new Promise((resolve, reject) => {
    +     this.addEventHandler(
    +       REGISTER_EVENT,
    +       (result) => {
    +         this.registered = true;
    +         resolve(result);
    +       },
    +       reject
    +     );
    +   });
    + } catch (error) {
    +   this.$webex.logger.error(`Error establishing connection: ${error}`);
    +   throw error;
    + }
    }

Committable suggestion was skipped due to low confidence.

packages/@webex/webex-core/src/lib/services/service-catalog.js (1)

273-273: ⚠️ Potential issue

Ensure Hostname Comparisons are Case-Insensitive

Hostnames are case-insensitive as per RFC 4343. The current code uses strict equality to compare hostnames, which could lead to mismatches if the hostnames differ in case (e.g., Example.com vs. example.com). To handle all cases correctly, consider normalizing the hostnames to lowercase before comparison.

Apply this diff to fix the issue:

-          if (inputUrl.hostname === defaultHostname) {
+          if (inputUrl.hostname.toLowerCase() === defaultHostname.toLowerCase()) {

...

-              if (inputUrl.hostname === alternateUrl.hostname) {
+              if (inputUrl.hostname.toLowerCase() === alternateUrl.hostname.toLowerCase()) {

Also applies to: 289-289

Copy link

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-3939.d3m3l2kee0btzx.amplifyapp.com

@Kesari3008 Kesari3008 merged commit 95385c3 into webex:feat/wxcc Oct 24, 2024
11 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
validated If the pull request is validated for automation.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants