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: add vue integration #167

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

feat: add vue integration #167

wants to merge 1 commit into from

Conversation

asd55667
Copy link

@asd55667 asd55667 commented Nov 11, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced comprehensive documentation for the @tryabby/vue package, covering the createAbby function and related hooks.
    • Added new classes for managing storage related to A/B testing and feature flags.
    • Implemented a robust architecture for A/B testing and feature flag management within Vue applications.
  • Bug Fixes

    • Enhanced error handling in the context management for A/B testing.
  • Tests

    • Established extensive unit tests for the useAbby hook and related functionalities, ensuring type safety and correct behavior.
    • Added mock API handlers and a testing server setup to streamline testing processes.
  • Chores

    • Updated configuration files for TypeScript, Vite, and bundling to improve development workflows and build processes.

Copy link

vercel bot commented Nov 11, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
abby-docs ❌ Failed (Inspect) Nov 11, 2024 7:48am

Copy link
Contributor

coderabbitai bot commented Nov 11, 2024

Walkthrough

This pull request introduces several significant changes to the @tryabby/vue package, including the addition of a new .gitignore entry for the dist directory, comprehensive documentation in a new README.md file, and the creation of a package.json file that outlines the package's structure and dependencies. Additionally, new functionalities are implemented through various TypeScript files, including storage services, context management for A/B testing, and utility functions for random selection. The changes also include multiple test files to ensure the correctness of the implemented features.

Changes

File Path Change Summary
packages/vue/.gitignore Added dist entry to ignore the distribution directory.
packages/vue/README.md Introduced documentation for the createAbby function, detailing its properties and associated React hooks, components, and utility functions.
packages/vue/package.json Created a new package.json specifying the package name, version, entry points, scripts, dependencies, and development dependencies.
packages/vue/src/StorageService.ts Added ABStorageService, FFStorageService, and RCStorageService classes for managing storage with methods for A/B testing, feature flags, and remote configuration.
packages/vue/src/context.ts Introduced context management for A/B testing and feature flags, including the createAbby function and several utility hooks.
packages/vue/src/helpers.ts Added types and functions for random number generation and weighted selection.
packages/vue/src/index.ts Updated exports to include new functionalities from context and core package.
packages/vue/tests/helpers.test.ts Added tests for getWeightedRandomVariant and getRandomDecimal functions.
packages/vue/tests/mocks/handlers.ts Introduced mock API handlers for testing using msw.
packages/vue/tests/mocks/server.ts Set up a request mocking server using msw.
packages/vue/tests/setup.ts Established a testing setup for the Vue application, including API mocking and cleanup routines.
packages/vue/tests/ssr.test.ts Created unit tests for the createAbby function focusing on server-side rendering behavior.
packages/vue/tests/types.test.ts Introduced tests for type correctness in createAbby and its hooks.
packages/vue/tests/useAbby.test.ts Added tests for the useAbby hook and its functionalities.
packages/vue/tests/utils.ts Introduced renderHook function for testing hooks within a Vue component context.
packages/vue/tsconfig.json Created a TypeScript configuration file extending from a base configuration.
packages/vue/tsup.config.ts Added configuration for the TypeScript bundler tsup, specifying build options.
packages/vue/vite.config.ts Introduced a Vite configuration file for the Vue project, including setup for testing.

Possibly related PRs

  • add remix package #136: The addition of the dist entry to the .gitignore file in the main PR is related to the packages/remix/.gitignore file, which also includes an entry to ignore the dist directory, indicating a similar intent to manage build artifacts across different packages.
  • feat(cli): add flag ai removal command #151: The main PR's changes to the .gitignore file align with the feature flag removal command introduced in this PR, as both involve managing files and configurations related to feature flags.
  • feat: use typescript 5 and remove ts-toolbelt depedency #152: The changes in the main PR regarding the .gitignore file may relate to the overall project structure and management, which is also a focus in this PR that updates TypeScript and removes dependencies.
  • feat(web): improve ab testing overview page #159: The improvements to the A/B testing overview page may connect with the changes in the main PR, as both involve enhancing the user experience and managing project configurations.
  • feat(web): add auto flag removal #161: The introduction of auto flag removal in this PR may relate to the changes in the main PR, as both involve managing feature flags and their configurations within the project.

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.

Copy link
Contributor

@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.

Actionable comments posted: 16

🧹 Outside diff range and nitpick comments (32)
packages/vue/tests/mocks/server.ts (1)

4-5: Consider enhancing the documentation.

While the current comment is helpful, it could be more descriptive by including:

  • The purpose of MSW in the testing context
  • How to use this server in tests
  • A link to MSW documentation
-// This configures a request mocking server with the given request handlers.
+/**
+ * Mock Service Worker (MSW) server setup for intercepting and mocking API requests during tests.
+ * Import and use this server in your test setup file to start/stop request interception.
+ * @see https://mswjs.io/docs/getting-started/integrate/node
+ */
 export const server = setupServer(...handlers);
packages/vue/tests/utils.ts (2)

1-2: Use import type for type-only imports.

The Component import is only used as a type. To optimize bundle size and follow TypeScript best practices, it should be imported using import type.

-import { defineComponent, Component, h } from 'vue'
+import { defineComponent, h } from 'vue'
+import type { Component } from 'vue'
import { mount } from '@vue/test-utils'
🧰 Tools
🪛 Biome

[error] 1-1: Some named imports are only used as types.

This import is only used as a type.

Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.

(lint/style/useImportType)


4-18: Consider enhancing the test utility's flexibility and documentation.

To improve reusability and maintainability:

  1. Consider making the rendered content configurable
  2. Add JSDoc documentation explaining the utility's purpose and usage
+/**
+ * A test utility for rendering Vue composition hooks within a component context.
+ * 
+ * @param callback - The hook or setup function to test
+ * @param wrapper - The wrapper component providing the context
+ * @param options - Optional configuration for the utility
+ * @returns The mounted wrapper for assertions
+ * 
+ * @example
+ * const { result } = renderHook(() => useMyHook(), MyProvider)
+ */
-export function renderHook<T>(callback: () => T, wrapper: Component) {
+export function renderHook<T>(
+    callback: () => T,
+    wrapper: Component,
+    options: { renderContent?: string } = { renderContent: 'child' }
+) {
     const ChildComponent = defineComponent({
         setup() {
             try {
                 return callback();
             } catch (error) {
                 console.error('Error in renderHook callback:', error);
                 throw error;
             }
         },
         render() {
-            return h('div', {}, 'child')
+            return h('div', {}, options.renderContent)
         }
     })
     return mount(wrapper, {
         slots: {
             default: () => h(ChildComponent)
         }
     })
 }
packages/vue/tests/setup.ts (3)

1-6: Consider modernizing the test setup imports.

  1. Replace node-fetch with native fetch:
    • For Node.js >= 18, you can use the built-in fetch API instead of node-fetch
  2. Consider adding proper types for jest-dom instead of using @ts-ignore:
    • Install @types/testing-library__jest-dom
-/// @ts-ignore it doesn't have types
import matchers from "@testing-library/jest-dom/matchers";
import { cleanup } from "@testing-library/vue";
-import fetch from "node-fetch";
import { afterEach, expect } from "vitest";
import { server } from "./mocks/server";

11-15: Add error handling for mock server lifecycle.

While the setup is correct, consider adding error handling to prevent test failures from hanging:

 // Establish API mocking before all tests.
-beforeAll(() => server.listen());
+beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

 // Clean up after the tests are finished.
-afterAll(() => server.close());
+afterAll(() => server.close().catch(console.error));

17-26: LGTM! Consider adding error boundaries.

The test cleanup implementation follows best practices. For additional robustness, consider wrapping the cleanup in a try-catch block to prevent individual cleanup failures from affecting other tests.

 afterEach(() => {
+  try {
     // Reset any request handlers that we may add during the tests,
     // so they don't affect other tests.
     server.resetHandlers();
     cleanup();
+  } catch (error) {
+    console.error('Error during test cleanup:', error);
+  }
 });
packages/vue/tests/mocks/handlers.ts (1)

4-31: Consider enhancing mock data structure and type safety.

While the mock data structure is valid, consider the following improvements:

  1. Add comments explaining what the weight arrays represent (e.g., variant distribution)
  2. Include more diverse test cases (e.g., edge cases, different data types)
  3. Consider using a type for the weights array to ensure valid values

Here's a suggested improvement:

 const returnData: AbbyDataResponse = {
   tests: [
     {
       name: "test",
+      // Weights represent equal distribution across 4 variants (25% each)
       weights: [1, 1, 1, 1] as const,
     },
     {
       name: "test2",
+      // Weights represent 100% for variant A, 0% for variant B
       weights: [1, 0] as const,
     },
+    {
+      name: "test3",
+      // Example of uneven distribution
+      weights: [2, 1] as const, // 66.6% A, 33.3% B
+    },
   ],
   // ... rest of the mock data
 };
packages/vue/tests/helpers.test.ts (3)

4-10: Enhance basic test coverage.

The current test only verifies that the return value is defined. Consider adding:

  • Type verification
  • Error cases for invalid inputs
 it("should only return valid values", () => {
   const variants = ["A", "B", "C"] as const;
+  // Test normal case
   const variant = getWeightedRandomVariant(variants);
   expect(variant).toBeDefined();
+  expect(variants).toContain(variant);
+
+  // Test error cases
+  expect(() => getWeightedRandomVariant([])).toThrow();
+  expect(() => getWeightedRandomVariant(variants, [0.5])).toThrow();
 });

12-27: Consider adding statistical distribution tests.

While the current tests verify basic weight functionality, they don't validate the actual distribution of variants over a larger sample size.

+  it("should maintain expected distribution", () => {
+    const variants = ["A", "B"] as const;
+    const weights = [0.3, 0.7];
+    const iterations = 10000;
+    const counts = { A: 0, B: 0 };
+
+    for (let i = 0; i < iterations; i++) {
+      const variant = getWeightedRandomVariant(variants, weights);
+      counts[variant]++;
+    }
+
+    // Allow 5% margin of error
+    expect(counts.A / iterations).toBeCloseTo(0.3, 1);
+    expect(counts.B / iterations).toBeCloseTo(0.7, 1);
+  });

30-38: Add distribution uniformity test for random decimal generation.

While the current test verifies the range, it doesn't validate the uniformity of the distribution.

+  it("should generate uniformly distributed numbers", () => {
+    const buckets = Array(10).fill(0);
+    const iterations = 10000;
+
+    for (let i = 0; i < iterations; i++) {
+      const decimal = getRandomDecimal();
+      const bucketIndex = Math.floor(decimal * 10);
+      buckets[bucketIndex]++;
+    }
+
+    // Each bucket should have roughly 10% of values
+    // Allow 3% margin of error
+    buckets.forEach(count => {
+      expect(count / iterations).toBeCloseTo(0.1, 1);
+    });
+  });
packages/vue/package.json (2)

4-4: Add a package description.

The description field is empty. Please add a meaningful description to help users understand the package's purpose when viewing it on the npm registry.

-  "description": "",
+  "description": "Vue integration for Abby - The A/B Testing Platform",

14-18: Add essential npm scripts.

Consider adding the following scripts for a more complete development workflow:

   "scripts": {
     "build": "tsup src/",
     "dev": "pnpm run build --watch",
-    "test": "vitest"
+    "test": "vitest",
+    "typecheck": "tsc --noEmit",
+    "lint": "eslint src --ext .ts,.tsx",
+    "prepublishOnly": "pnpm run build"
   },
packages/vue/src/StorageService.ts (2)

10-10: Consider reducing the default cookie duration

A 365-day cookie duration might be excessive and could raise privacy concerns. Consider:

  1. Reducing the duration to a shorter period (e.g., 30 or 90 days)
  2. Making it configurable through the options parameter
  3. Adding a comment explaining why this duration was chosen
-const DEFAULT_COOKIE_AGE = 365;
+// Duration for persistent A/B test assignments and feature flags
+const DEFAULT_COOKIE_AGE = 90; // 90 days provides good balance between persistence and privacy

74-76: Consider adding configuration options

The current implementation exports pre-configured instances, which might limit flexibility. Consider:

  1. Allowing custom cookie options (domain, path, secure, etc.)
  2. Supporting different storage backends (localStorage, sessionStorage)
  3. Enabling custom error handling

Example approach:

export interface StorageServiceConfig {
  cookieOptions?: Cookie.CookieAttributes;
  onError?: (error: Error) => void;
  storage?: 'cookie' | 'localStorage' | 'sessionStorage';
}

export function createStorageServices(config?: StorageServiceConfig) {
  return {
    TestStorageService: new ABStorageService(config),
    FlagStorageService: new FFStorageService(config),
    RemoteConfigStorageService: new RCStorageService(config),
  };
}
packages/vue/tests/types.test.ts (2)

15-51: Consider enhancing test coverage for useAbby.

While the type checking is good, consider adding these test cases:

  1. Error handling when invalid variant is provided
  2. Validation of the actual variant values against the defined variants
  3. Edge cases like empty variant arrays

Also, remove the unnecessary empty lines 42-43 for better code organization.


116-149: Enhance useRemoteConfig test coverage.

While the type checking is comprehensive, consider adding these test cases:

  1. Error handling for invalid config types
  2. Validation of actual values matching their declared types
  3. Edge cases like null or undefined values

Example test cases to add:

it("handles invalid config types", () => {
  // Test invalid type assignments
  // Test null/undefined scenarios
});

it("validates actual values match declared types", () => {
  // Test string values are actually strings
  // Test number values are actually numbers
  // Test JSON values are valid JSON
});
packages/vue/tests/ssr.test.ts (6)

1-3: Optimize imports with type imports

Consider using explicit type imports for better tree-shaking and compilation optimization.

-import { defineComponent, Fragment, h, VNode } from 'vue'
+import { defineComponent, Fragment, h, type VNode } from 'vue'
🧰 Tools
🪛 Biome

[error] 1-1: Some named imports are only used as types.

This import is only used as a type.

Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.

(lint/style/useImportType)


36-37: Document the reason for ts-ignore

The ts-ignore comment should include a more detailed explanation of why it's necessary and what types are causing issues.

-/* @ts-ignore this is just the types for SSR */
+/* @ts-ignore Types for SSR don't properly recognize the variant type narrowing in the render function */

16-60: Consider adding more test cases

While the current test verifies basic SSR behavior, consider adding tests for:

  1. Error states
  2. Different variant combinations
  3. Edge cases with empty/invalid data

Would you like me to help generate additional test cases?


72-73: Remove extra empty line

There's an unnecessary double empty line between the createAbby setup and the component definition.


110-111: Rename describe block to match the hook name

The describe block name should match the hook being tested.

-describe("getRemoteConfig", () => {
+describe("useRemoteConfig", () => {

131-141: Remove unnecessary feature flag data

The test for remote config includes unused feature flag data in the initialData. Consider removing it to keep the test focused on remote config functionality.

 initialData: {
-  flags: [
-    {
-      value: true,
-      name: "test",
-    },
-    {
-      value: false,
-      name: "test2",
-    },
-  ],
+  flags: [],
   tests: [],
   remoteConfig: [{ name: "remoteConfig1", value: "FooBar" }],
 }
packages/vue/README.md (2)

57-71: Improve clarity of settings documentation

The settings documentation could be clearer with:

  1. A complete example showing both defaultValues and devOverrides
  2. Type definitions for the configuration object

Consider adding this example:

const abby = createAbby({
  // ... other config
  settings: {
    flags: {
      defaultValues: {
        "Boolean": false,
        "String": "",
        "Number": 0,
        "JSON": {}
      },
      devOverrides: {
        "my-boolean-flag": true,
        "my-string-flag": "dev-value"
      }
    }
  }
});
🧰 Tools
🪛 LanguageTool

[uncategorized] ~57-~57: Loose punctuation mark.
Context: ... are available: - flags.defaultValues: Allows you to set a general default val...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~69-~69: Loose punctuation mark.
Context: ...N": {} } ``` - flags.devOverrides: An object containing the values of feat...

(UNLIKELY_OPENING_PUNCTUATION)


21-21: Fix grammar and formatting issues

Please address these issues:

  1. Line 21: "They keys" should be "The keys"
  2. Lines 76, 92, 104: Capitalize "React" as it's a proper noun
  3. Line 109: Add period after "etc" in American English
  4. Line 135: Add hyphen in "higher-order function"

Also applies to: 76-76, 92-92, 104-104, 109-109, 135-135

🧰 Tools
🪛 LanguageTool

[grammar] ~21-~21: The pronoun ‘They’ must be used with a non-third-person form of a verb.
Context: ...ashboard to copy the tests object. They keys of the object represent the names of yo...

(NON3PRS_VERB)

packages/vue/src/helpers.ts (1)

1-10: Ensure proper attribution for external code sources

The code segments at lines 1-10 are taken from StackOverflow. Ensure that the code usage complies with licensing requirements, and consider providing proper attribution if necessary.

packages/vue/src/context.ts (5)

148-148: Remove unnecessary debugging console.log statement

There's a console.log statement on line 148 that appears to be used for debugging purposes. Consider removing it to clean up the production code.

Apply this diff to remove the console.log statement:

-          console.log(1123, selectedVariant.value);

199-199: Fix typo in comment for useFeatureFlags

There's a typographical error in the comment on line 199:

  • "Retruns" should be "Returns"

Apply this diff to correct the typo:

-       * Retruns an Array of all flags with their name and value
+       * Returns an array of all flags with their name and value

210-210: Fix typos in comment for useRemoteConfigVariables

There are typographical errors in the comment on line 210:

  • "Retruns" should be "Returns"
  • "rmeote" should be "remote"

Apply this diff to correct the typos:

-       * Retruns an Array of all rmeote config variables with their name and value
+       * Returns an array of all remote config variables with their name and value

198-198: Consider updating JSDoc for clarity

The JSDoc comment for useFeatureFlags could be updated for clarity and consistency:

  • Use proper punctuation and capitalization.
  • Ensure the description accurately reflects the function's behavior.

Apply this diff to enhance the comment:

-  /**
-   * Returns an array of all flags with their name and value
-   */
+  /**
+   * Returns an array of all feature flags with their names and values.
+   */

209-209: Enhance JSDoc for useRemoteConfigVariables

For better clarity, consider updating the JSDoc comment on line 209:

Apply this diff to improve the comment:

-  /**
-   * Returns an array of all remote config variables with their name and value
-   */
+  /**
+   * Returns an array of all remote configuration variables with their names and values.
+   */
packages/vue/tests/useAbby.test.ts (2)

297-297: Typographical Error in Test Description

There's a typo in the test description: duplicate 'a' in "with a a lookup object". Please remove the extra 'a'.

Apply this correction:

- it("produces proper types with a a lookup object in the hook", () => {
+ it("produces proper types with a lookup object in the hook", () => {

387-416: Organize Tests Within 'describe' Blocks

For better structure and readability, it's recommended to wrap all it blocks within describe blocks.

Example:

+describe("Type Assertions", () => {
  it("has the correct types", () => {
    // test code
  });
+});

+describe("useFeatureFlags()", () => {
  // existing tests...
+});

This helps group related tests together and improves test organization.

Also applies to: 418-491

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f018ef1 and 9810bc6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • packages/vue/.gitignore (1 hunks)
  • packages/vue/README.md (1 hunks)
  • packages/vue/package.json (1 hunks)
  • packages/vue/src/StorageService.ts (1 hunks)
  • packages/vue/src/context.ts (1 hunks)
  • packages/vue/src/helpers.ts (1 hunks)
  • packages/vue/src/index.ts (1 hunks)
  • packages/vue/tests/helpers.test.ts (1 hunks)
  • packages/vue/tests/mocks/handlers.ts (1 hunks)
  • packages/vue/tests/mocks/server.ts (1 hunks)
  • packages/vue/tests/setup.ts (1 hunks)
  • packages/vue/tests/ssr.test.ts (1 hunks)
  • packages/vue/tests/types.test.ts (1 hunks)
  • packages/vue/tests/useAbby.test.ts (1 hunks)
  • packages/vue/tests/utils.ts (1 hunks)
  • packages/vue/tsconfig.json (1 hunks)
  • packages/vue/tsup.config.ts (1 hunks)
  • packages/vue/vite.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/vue/.gitignore
  • packages/vue/tsconfig.json
  • packages/vue/tsup.config.ts
🧰 Additional context used
🪛 LanguageTool
packages/vue/README.md

[grammar] ~21-~21: The pronoun ‘They’ must be used with a non-third-person form of a verb.
Context: ...ashboard to copy the tests object. They keys of the object represent the names of yo...

(NON3PRS_VERB)


[uncategorized] ~57-~57: Loose punctuation mark.
Context: ... are available: - flags.defaultValues: Allows you to set a general default val...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~69-~69: Loose punctuation mark.
Context: ...N": {} } ``` - flags.devOverrides: An object containing the values of feat...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~76-~76: “React” is a proper noun and needs to be capitalized.
Context: ...rn Values #### useAbby useAbby is a react hook that used to access the value of a...

(A_GOOGLE)


[uncategorized] ~82-~82: Loose punctuation mark.
Context: ...ed weights ##### Parameters - string: The name of the test or flag, needs to ...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~82-~82: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...string: The name of the test or flag, needs to be one of the defined tests. ##### Ret...

(REP_NEED_TO_VB)


[uncategorized] ~86-~86: Loose punctuation mark.
Context: ...ests. ##### Return Values - variant : The variant of the test - onAct: A f...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~88-~88: Loose punctuation mark.
Context: ...nt: The variant of the test -onAct`: A function to call when the user perfor...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~92-~92: “React” is a proper noun and needs to be capitalized.
Context: ...# useFeatureFlag useFeatureFlag is a react hook that used to access the value of a...

(A_GOOGLE)


[grammar] ~104-~104: “React” is a proper noun and needs to be capitalized.
Context: ...Type: boolean #### AbbyProvider A react component to wrap your application. ##...

(A_GOOGLE)


[uncategorized] ~108-~108: Loose punctuation mark.
Context: ... application. ##### Props - children: The children of the component - `initia...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~109-~109: In American English, abbreviations like “etc.” require a period.
Context: ... (optional)`: The data (weights, tests, etc). If not provided, the data will be fet...

(ETC_PERIOD)


[uncategorized] ~122-~122: A comma may be missing after the conjunctive/linking adverb ‘Otherwise’.
Context: ...ts, persisted in a cookie and returned. Otherwise the variant will be read from the cooki...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[formatting] ~127-~127: If the ‘needs’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...ned. ##### Parameters The name of the test, needs to be one of the defined tests. ##### ...

(COMMA_AFTER_PREPOSITION_PHRASES)


[uncategorized] ~135-~135: Did you mean the adjective “higher-order” (spelled with a hyphen)?
Context: ... #### withDevtools withDevtools is a higher order function to wrap the Devtools from [`@t...

(HIGHER_ORDER_HYPHEN)


[uncategorized] ~151-~151: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...r. This means the cookie will be deleted and the user will get a new variant on the ...

(COMMA_COMPOUND_SENTENCE_2)


[formatting] ~155-~155: If the ‘needs’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...load. #### Parameters The name of the test, needs to be one of the defined tests. #### E...

(COMMA_AFTER_PREPOSITION_PHRASES)

🪛 Biome
packages/vue/src/context.ts

[error] 11-11: Some named imports are only used as types.

This import is only used as a type.

This import is only used as a type.

This import is only used as a type.

This import is only used as a type.

Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.

(lint/style/useImportType)


[error] 11-11: This import is unused.

Unused imports might be the result of an incomplete refactoring.
Safe fix: Remove the unused import.

(lint/correctness/noUnusedImports)


[error] 11-11: This import is unused.

Unused imports might be the result of an incomplete refactoring.
Safe fix: Remove the unused import.

(lint/correctness/noUnusedImports)

packages/vue/tests/ssr.test.ts

[error] 1-1: Some named imports are only used as types.

This import is only used as a type.

Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.

(lint/style/useImportType)

packages/vue/tests/utils.ts

[error] 1-1: Some named imports are only used as types.

This import is only used as a type.

Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.

(lint/style/useImportType)

🔇 Additional comments (17)
packages/vue/src/index.ts (1)

1-6: LGTM! Verify dependencies and local imports.

The export structure looks clean and follows TypeScript best practices.

Let's verify the dependencies and local imports:

✅ Verification successful

The previous results show that @tryabby/core is properly declared as a workspace dependency, but we need to verify the actual exports in context.ts since ast-grep didn't return any matches. Let's examine the full content of these files to make a proper assessment.


Exports verified and properly implemented

The exports in index.ts are correctly implemented and match their source declarations:

  • All types and functions from context.ts are properly defined and exported: createAbby, withDevtoolsFunction, and ABTestReturnValue
  • The @tryabby/core dependency is correctly declared in package.json as a workspace dependency
  • The re-exports from @tryabby/core (ABConfig, AbbyConfig, defineConfig) are valid as the package is a direct dependency
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify package dependencies and local imports

# Test 1: Check if @tryabby/core is declared in package.json
echo "Checking @tryabby/core dependency..."
jq '.dependencies["@tryabby/core"] // .peerDependencies["@tryabby/core"]' packages/vue/package.json

# Test 2: Verify the existence of exported entities in context.ts
echo "Checking local exports from context.ts..."
ast-grep --pattern 'export const createAbby' packages/vue/src/context.ts
ast-grep --pattern 'export type withDevtoolsFunction' packages/vue/src/context.ts
ast-grep --pattern 'export type ABTestReturnValue' packages/vue/src/context.ts

Length of output: 531


Script:

#!/bin/bash
# Let's check the actual content of context.ts to verify exports
echo "Content of context.ts:"
cat packages/vue/src/context.ts

# Also check package.json to understand the full dependency structure
echo -e "\nContent of package.json:"
cat packages/vue/package.json

Length of output: 12139

packages/vue/tests/mocks/server.ts (1)

1-5: LGTM! Clean and standard MSW setup.

The implementation follows MSW best practices with proper separation of concerns between server setup and handlers.

packages/vue/vite.config.ts (2)

1-4: LGTM! Type references and imports are properly configured.

The necessary imports and type references are correctly set up for Vue and Vitest integration.


6-13: Verify test setup configuration and file existence.

The configuration looks good, but let's verify the test setup:

  1. Ensure the setup file exists
  2. Consider adding transformMode for Vue components

Let's verify the setup:

Consider adding the following configuration if you plan to test Vue components:

 export default defineConfig({
   plugins: [vue()],
   test: {
     globals: true,
     environment: "jsdom",
     setupFiles: "./tests/setup.ts",
+    transformMode: {
+      web: [/\.[jt]sx$/],
+    }
   },
 });
✅ Verification successful

Test setup is properly configured and all dependencies are in place

The verification shows that:

  1. The setup file exists and contains proper configuration including:
    • Jest DOM matchers integration
    • Vue testing library cleanup
    • MSW server setup for API mocking
    • Global fetch polyfill
  2. Required testing dependencies are present in package.json:
    • @testing-library/vue
    • @vue/test-utils
    • jsdom

The current configuration is sufficient for Vue component testing, and the suggested transformMode addition isn't necessary as the Vue plugin already handles the transformations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify test setup file exists and check its contents
if [ -f "packages/vue/tests/setup.ts" ]; then
    echo "Setup file exists"
    cat "packages/vue/tests/setup.ts"
else
    echo "Warning: Setup file not found at packages/vue/tests/setup.ts"
fi

# Check for Vue test utils in package.json
if [ -f "packages/vue/package.json" ]; then
    echo "Checking for @vue/test-utils dependency..."
    cat "packages/vue/package.json" | grep -A 5 -B 5 "@vue/test-utils"
fi

Length of output: 1452

packages/vue/tests/utils.ts (1)

4-18: ⚠️ Potential issue

Fix render implementation and enhance test utility robustness.

There are several issues that need to be addressed:

  1. The render function implementation is incorrect - it's returning a function instead of the VNode directly
  2. The callback execution should include error handling
  3. The mount result should be returned for test interactions
  4. The callback type could be more specific

Here's the corrected implementation:

-export function renderHook(callback: () => void, wrapper: Component) {
+export function renderHook<T>(callback: () => T, wrapper: Component) {
     const ChildComponent = defineComponent({
         setup() {
-            callback?.();
+            try {
+                return callback();
+            } catch (error) {
+                console.error('Error in renderHook callback:', error);
+                throw error;
+            }
         },
         render() {
-            return () => h('div', {}, 'child')
+            return h('div', {}, 'child')
         }
     })
-    mount(wrapper, {
+    return mount(wrapper, {
         slots: {
             default: () => h(ChildComponent)
         }
     })
 }

The changes:

  • Made the function generic to preserve the return type of the callback
  • Added error handling for the callback execution
  • Fixed the render function to return VNode directly
  • Return the mount result for test interactions

Let's verify if this utility is being used correctly in tests:

packages/vue/tests/mocks/handlers.ts (2)

1-2: LGTM! Imports are well-structured.

The necessary dependencies and types are correctly imported from their respective packages.


1-42: Verify consistency with other platform integrations.

Let's ensure this testing approach aligns with other platform integrations (React, Angular, etc.) for consistency.

✅ Verification successful

Testing approach is consistent across platform integrations

The verification shows that all platform packages (React, Vue, Next.js, Svelte, Node, Remix) maintain consistent test mocks:

  • All use the same AbbyDataResponse type from @tryabby/core
  • Identical MSW rest handler patterns for mocking API endpoints
  • Consistent mock data structure across implementations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if similar test mocks exist in other platform packages
# and verify the consistency of the testing approach

# Search for similar mock handlers in other packages
echo "Searching for similar mock handlers in other packages..."
fd -t f "handlers.ts" packages/ --exec rg -l "AbbyDataResponse"

# Check for MSW usage in other packages
echo "Checking MSW usage in other packages..."
fd "package.json" packages/ --exec rg -l "msw"

Length of output: 809


Script:

#!/bin/bash
# Let's verify the consistency of mock handlers across packages

# Check the content of handlers.ts files to verify similar structure
echo "=== Checking handlers.ts content across packages ==="
for file in $(fd -t f "handlers.ts" packages/); do
  echo "=== $file ==="
  rg -A 5 "AbbyDataResponse" "$file"
done

# Verify MSW rest handler usage pattern
echo "=== Checking MSW rest handler usage ==="
for file in $(fd -t f "handlers.ts" packages/); do
  echo "=== $file ==="
  rg "rest\." "$file"
done

Length of output: 5856

packages/vue/tests/helpers.test.ts (1)

1-2: LGTM!

The imports correctly reference the helper functions being tested.

packages/vue/package.json (2)

40-46: Dependencies configuration looks good!

The dependencies and peerDependencies are correctly configured:

  • Vue is properly specified as a peer dependency
  • Workspace dependencies are using the correct protocol
  • Runtime dependencies are appropriate

2-2: Verify package name availability.

Let's ensure the package name is available on npm before publishing.

✅ Verification successful

Package name @tryabby/vue is available on npm registry

The package name @tryabby/vue is currently available and can be published to npm.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the package name is available on npm
npm view @tryabby/vue version || echo "Package name is available"

Length of output: 711

packages/vue/src/StorageService.ts (1)

1-76: Verify secure cookie implementation

Please ensure secure cookie handling:

  1. Consider adding the secure flag for HTTPS-only cookies
  2. Add the sameSite attribute to prevent CSRF
  3. Validate and sanitize values before storage to prevent XSS
packages/vue/tests/types.test.ts (2)

1-13: LGTM! Test setup follows best practices.

The environment management is well-implemented with proper backup and restoration of process.env, and module cache clearing between tests.


72-88: ⚠️ Potential issue

Address the incomplete devOverrides type checking implementation.

The skipped test and TODO comment indicate that devOverrides type checking is not working yet. This could lead to runtime issues if not properly implemented.

Let's verify if this is a known issue:

Please either:

  1. Implement the type checking for devOverrides
  2. Create a detailed issue explaining the problem and tracking its resolution
  3. Add more context to the TODO comment explaining why the types don't work
packages/vue/tests/ssr.test.ts (2)

5-14: LGTM: Clean test environment setup!

The environment setup follows testing best practices by properly managing environment variables between tests.


1-149: Overall implementation looks solid!

The test suite provides good coverage for SSR scenarios across all main hooks (useAbby, useFeatureFlag, useRemoteConfig). The implementation aligns well with the Vue integration objectives and follows Vue testing best practices.

🧰 Tools
🪛 Biome

[error] 1-1: Some named imports are only used as types.

This import is only used as a type.

Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.

(lint/style/useImportType)

packages/vue/README.md (1)

1-2: Verify Vue implementation in source files

Let's verify that the source files actually implement Vue integration correctly.

✅ Verification successful

Vue integration is properly implemented

The codebase correctly implements Vue-specific integration:

  • Uses Vue's composition API with proper imports (defineComponent, ref, inject, etc.)
  • Implements Vue-specific provider pattern using InjectionKey and provide/inject
  • Correctly handles component lifecycle with Vue hooks (onMounted, onBeforeUnmount, etc.)
  • Properly implements Vue's rendering system using h and Fragment
  • Contains Vue-specific composables (useAbby, useFeatureFlag, etc.)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify Vue-specific implementation files exist and don't contain React code

# Check for Vue-specific files and implementations
echo "Checking for Vue files..."
fd -e vue -e ts . packages/vue/src

# Look for potential React remnants
echo "Checking for React terminology..."
rg -i 'react|jsx|tsx' packages/vue/src

Length of output: 332


Script:

#!/bin/bash
# Let's examine the content of these Vue integration files

# Check the main implementation file
echo "=== Checking index.ts ==="
cat packages/vue/src/index.ts

# Check the context implementation
echo -e "\n=== Checking context.ts ==="
cat packages/vue/src/context.ts

# Check for Vue-specific imports and usage
echo -e "\n=== Checking Vue-specific implementations ==="
rg -i "vue|ref|computed|defineComponent|composable" packages/vue/src

Length of output: 12911

packages/vue/src/helpers.ts (1)

14-23: Implementation of getRandomDecimal is correct

The function correctly generates a random decimal number using crypto.getRandomValues, with a fallback to Math.random(). This ensures better randomness and security.

Comment on lines +8 to +9
/// @ts-ignore
global.fetch = fetch;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unnecessary global fetch override.

For Node.js >= 18, the global fetch API is already available, making this override unnecessary. If you need to support older Node.js versions, consider using a conditional check.

-/// @ts-ignore
-global.fetch = fetch;
+// Remove this section if using Node.js >= 18
+// For older versions, consider:
+if (!global.fetch) {
+  const { fetch } = require('node-fetch');
+  global.fetch = fetch;
+}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +32 to +42
export const handlers = [
rest.get(
`${ABBY_BASE_URL}api/dashboard/:projectId/data`,
(_req, res, ctx) => {
return res(ctx.json(returnData));
}
),
rest.get(`${ABBY_BASE_URL}api/v1/data/:projectId`, (_req, res, ctx) => {
return res(ctx.json(returnData));
}),
];
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance API handlers with more test scenarios.

The current handlers only cover the happy path. Consider adding:

  1. Error scenarios (e.g., invalid projectId, server errors)
  2. Response delays to test loading states
  3. Different responses based on projectId

Here's a suggested implementation:

 export const handlers = [
   rest.get(
     `${ABBY_BASE_URL}api/dashboard/:projectId/data`,
     (_req, res, ctx) => {
+      const { projectId } = _req.params;
+      
+      // Mock error for specific projectId
+      if (projectId === 'invalid') {
+        return res(
+          ctx.status(404),
+          ctx.json({ error: 'Project not found' })
+        );
+      }
+
+      // Add artificial delay to test loading states
+      return res(
+        ctx.delay(100),
+        ctx.json(returnData)
+      );
     }
   ),
   rest.get(`${ABBY_BASE_URL}api/v1/data/:projectId`, (_req, res, ctx) => {
+    const { projectId } = _req.params;
+    
+    // Mock server error
+    if (projectId === 'error') {
+      return res(
+        ctx.status(500),
+        ctx.json({ error: 'Internal server error' })
+      );
+    }
+
     return res(ctx.json(returnData));
   }),
 ];
📝 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.

Suggested change
export const handlers = [
rest.get(
`${ABBY_BASE_URL}api/dashboard/:projectId/data`,
(_req, res, ctx) => {
return res(ctx.json(returnData));
}
),
rest.get(`${ABBY_BASE_URL}api/v1/data/:projectId`, (_req, res, ctx) => {
return res(ctx.json(returnData));
}),
];
export const handlers = [
rest.get(
`${ABBY_BASE_URL}api/dashboard/:projectId/data`,
(_req, res, ctx) => {
const { projectId } = _req.params;
// Mock error for specific projectId
if (projectId === 'invalid') {
return res(
ctx.status(404),
ctx.json({ error: 'Project not found' })
);
}
// Add artificial delay to test loading states
return res(
ctx.delay(100),
ctx.json(returnData)
);
}
),
rest.get(`${ABBY_BASE_URL}api/v1/data/:projectId`, (_req, res, ctx) => {
const { projectId } = _req.params;
// Mock server error
if (projectId === 'error') {
return res(
ctx.status(500),
ctx.json({ error: 'Internal server error' })
);
}
return res(ctx.json(returnData));
}),
];

Comment on lines +23 to +39
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/vue": "^8.1.0",
"@vue/test-utils": "^2.4.6",
"@tryabby/devtools": "workspace:*",
"@types/js-cookie": "^3.0.3",
"@vitejs/plugin-vue": "5.1.4",
"jsdom": "^20.0.3",
"msw": "^0.49.1",
"node-fetch": "^3.3.0",
"tsconfig": "workspace:*",
"tsup": "^6.5.0",
"typescript": "5.5.4",
"vite": "5.4.0",
"vitest": "2.0.5"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Clean up development dependencies.

There are several issues with the devDependencies:

  1. React-related testing packages are included but not needed for a Vue package
  2. Vue is missing from devDependencies
  3. Version patterns are inconsistent

Apply these changes:

   "devDependencies": {
-    "@testing-library/jest-dom": "^5.16.5",
-    "@testing-library/react": "^13.4.0",
     "@testing-library/vue": "^8.1.0",
     "@vue/test-utils": "^2.4.6",
     "@tryabby/devtools": "workspace:*",
     "@types/js-cookie": "^3.0.3",
     "@vitejs/plugin-vue": "5.1.4",
     "jsdom": "^20.0.3",
     "msw": "^0.49.1",
     "node-fetch": "^3.3.0",
     "tsconfig": "workspace:*",
     "tsup": "^6.5.0",
     "typescript": "5.5.4",
     "vite": "5.4.0",
-    "vitest": "2.0.5"
+    "vitest": "2.0.5",
+    "vue": "^3.5.12"
   },
📝 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.

Suggested change
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/vue": "^8.1.0",
"@vue/test-utils": "^2.4.6",
"@tryabby/devtools": "workspace:*",
"@types/js-cookie": "^3.0.3",
"@vitejs/plugin-vue": "5.1.4",
"jsdom": "^20.0.3",
"msw": "^0.49.1",
"node-fetch": "^3.3.0",
"tsconfig": "workspace:*",
"tsup": "^6.5.0",
"typescript": "5.5.4",
"vite": "5.4.0",
"vitest": "2.0.5"
},
"devDependencies": {
"@testing-library/vue": "^8.1.0",
"@vue/test-utils": "^2.4.6",
"@tryabby/devtools": "workspace:*",
"@types/js-cookie": "^3.0.3",
"@vitejs/plugin-vue": "5.1.4",
"jsdom": "^20.0.3",
"msw": "^0.49.1",
"node-fetch": "^3.3.0",
"tsconfig": "workspace:*",
"tsup": "^6.5.0",
"typescript": "5.5.4",
"vite": "5.4.0",
"vitest": "2.0.5",
"vue": "^3.5.12"
},

Comment on lines +12 to +36
class ABStorageService implements IStorageService {
get(projectId: string, testName: string): string | null {
const retrievedValue = Cookie.get(getABStorageKey(projectId, testName));
if (!retrievedValue) return null;

return retrievedValue;
}

set(
projectId: string,
testName: string,
value: string,
options?: StorageServiceOptions
): void {
Cookie.set(getABStorageKey(projectId, testName), value, {
expires: options?.expiresInDays
? options.expiresInDays
: DEFAULT_COOKIE_AGE,
});
}

remove(projectId: string, testName: string): void {
Cookie.remove(getABStorageKey(projectId, testName));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and type validation

The ABStorageService implementation should handle potential cookie-related errors and validate input types:

 class ABStorageService implements IStorageService {
   get(projectId: string, testName: string): string | null {
+    try {
       const retrievedValue = Cookie.get(getABStorageKey(projectId, testName));
       if (!retrievedValue) return null;
       return retrievedValue;
+    } catch (error) {
+      console.error(`Failed to retrieve A/B test value: ${error}`);
+      return null;
+    }
   }

   set(
     projectId: string,
     testName: string,
     value: string,
     options?: StorageServiceOptions
   ): void {
+    if (!projectId || !testName) {
+      throw new Error('Project ID and test name are required');
+    }
+    try {
       Cookie.set(getABStorageKey(projectId, testName), value, {
         expires: options?.expiresInDays
           ? options.expiresInDays
           : DEFAULT_COOKIE_AGE,
       });
+    } catch (error) {
+      console.error(`Failed to set A/B test value: ${error}`);
+      throw error;
+    }
   }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +38 to +55
class FFStorageService implements IStorageService {
get(projectId: string, flagName: string): string | null {
const retrievedValue = Cookie.get(getFFStorageKey(projectId, flagName));
if (!retrievedValue) return null;

return retrievedValue;
}

set(projectId: string, flagName: string, value: string): void {
Cookie.set(getFFStorageKey(projectId, flagName), value, {
expires: DEFAULT_COOKIE_AGE,
});
}

remove(projectId: string, flagName: string): void {
Cookie.remove(getFFStorageKey(projectId, flagName));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reduce code duplication and standardize API

Consider creating a base storage service class to reduce duplication and maintain consistency:

+abstract class BaseStorageService implements IStorageService {
+  constructor(protected getStorageKey: (projectId: string, key: string) => string) {}
+
+  get(projectId: string, key: string): string | null {
+    try {
+      const retrievedValue = Cookie.get(this.getStorageKey(projectId, key));
+      return retrievedValue ?? null;
+    } catch (error) {
+      console.error(`Failed to retrieve value: ${error}`);
+      return null;
+    }
+  }
+
+  set(projectId: string, key: string, value: string, options?: StorageServiceOptions): void {
+    if (!projectId || !key) {
+      throw new Error('Project ID and key are required');
+    }
+    try {
+      Cookie.set(this.getStorageKey(projectId, key), value, {
+        expires: options?.expiresInDays ?? DEFAULT_COOKIE_AGE,
+      });
+    } catch (error) {
+      console.error(`Failed to set value: ${error}`);
+      throw error;
+    }
+  }
+
+  remove(projectId: string, key: string): void {
+    Cookie.remove(this.getStorageKey(projectId, key));
+  }
+}

-class FFStorageService implements IStorageService {
+class FFStorageService extends BaseStorageService {
+  constructor() {
+    super(getFFStorageKey);
+  }
-  // Remove duplicated methods
}
📝 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.

Suggested change
class FFStorageService implements IStorageService {
get(projectId: string, flagName: string): string | null {
const retrievedValue = Cookie.get(getFFStorageKey(projectId, flagName));
if (!retrievedValue) return null;
return retrievedValue;
}
set(projectId: string, flagName: string, value: string): void {
Cookie.set(getFFStorageKey(projectId, flagName), value, {
expires: DEFAULT_COOKIE_AGE,
});
}
remove(projectId: string, flagName: string): void {
Cookie.remove(getFFStorageKey(projectId, flagName));
}
}
abstract class BaseStorageService implements IStorageService {
constructor(protected getStorageKey: (projectId: string, key: string) => string) {}
get(projectId: string, key: string): string | null {
try {
const retrievedValue = Cookie.get(this.getStorageKey(projectId, key));
return retrievedValue ?? null;
} catch (error) {
console.error(`Failed to retrieve value: ${error}`);
return null;
}
}
set(projectId: string, key: string, value: string, options?: StorageServiceOptions): void {
if (!projectId || !key) {
throw new Error('Project ID and key are required');
}
try {
Cookie.set(this.getStorageKey(projectId, key), value, {
expires: options?.expiresInDays ?? DEFAULT_COOKIE_AGE,
});
} catch (error) {
console.error(`Failed to set value: ${error}`);
throw error;
}
}
remove(projectId: string, key: string): void {
Cookie.remove(this.getStorageKey(projectId, key));
}
}
class FFStorageService extends BaseStorageService {
constructor() {
super(getFFStorageKey);
}
}

import { HttpService } from "@tryabby/core";
import { type AbbyDataResponse, AbbyEventType } from "@tryabby/core";
import type { AbbyDevtoolProps, DevtoolsFactory } from "@tryabby/devtools";
import { defineComponent, PropType, h, ref, Ref, Component, InjectionKey, provide, inject, watch, watchEffect, Fragment, VNode, onBeforeUpdate, onBeforeUnmount, onUpdated, onMounted, useSlots, onBeforeMount } from 'vue'
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize imports by using import type and removing unused imports

Some imports on line 11 are only used as types or are unused. To improve tree-shaking and avoid loading unnecessary modules, use import type for type-only imports and remove any unused imports.

Apply this diff to fix the imports:

-import { defineComponent, PropType, h, ref, Ref, Component, InjectionKey, provide, inject, watch, watchEffect, Fragment, VNode, onBeforeUpdate, onBeforeUnmount, onUpdated, onMounted, useSlots, onBeforeMount } from 'vue'
+import { defineComponent, h, ref, provide, inject, watch, watchEffect, Fragment, onBeforeUpdate, onBeforeUnmount, onMounted, useSlots, onBeforeMount } from 'vue'
+import type { PropType, Ref, Component, InjectionKey, VNode } from 'vue'
📝 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.

Suggested change
import { defineComponent, PropType, h, ref, Ref, Component, InjectionKey, provide, inject, watch, watchEffect, Fragment, VNode, onBeforeUpdate, onBeforeUnmount, onUpdated, onMounted, useSlots, onBeforeMount } from 'vue'
import { defineComponent, h, ref, provide, inject, watch, watchEffect, Fragment, onBeforeUpdate, onBeforeUnmount, onMounted, useSlots, onBeforeMount } from 'vue'
import type { PropType, Ref, Component, InjectionKey, VNode } from 'vue'
🧰 Tools
🪛 Biome

[error] 11-11: Some named imports are only used as types.

This import is only used as a type.

This import is only used as a type.

This import is only used as a type.

This import is only used as a type.

Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.

(lint/style/useImportType)


[error] 11-11: This import is unused.

Unused imports might be the result of an incomplete refactoring.
Safe fix: Remove the unused import.

(lint/correctness/noUnusedImports)


[error] 11-11: This import is unused.

Unused imports might be the result of an incomplete refactoring.
Safe fix: Remove the unused import.

(lint/correctness/noUnusedImports)

renderHook(() => {
const flag1 = useFeatureFlag("flag1");
// wait for the flag to be fetched
waitFor(() => expect(flag1).toEqual(true));
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Await 'waitFor' Calls and Mark Test Functions as Asynchronous

The waitFor function is asynchronous and returns a Promise. You need to await the waitFor calls and mark the test functions as async to ensure assertions execute after asynchronous operations complete.

Example fix for one of the test cases:

-it("should return the correct feature flags", () => {
+it("should return the correct feature flags", async () => {
    renderHook(() => {
      const flag1 = useFeatureFlag("flag1");
-     waitFor(() => expect(flag1).toEqual(true));
+     await waitFor(() => expect(flag1).toEqual(true));
    }, AbbyProvider);
});

Apply this change to all test cases where waitFor is used.

Also applies to: 171-171, 188-188, 213-213, 233-233, 358-358, 382-382, 448-448, 486-486

C: "Hola",
});

expectTypeOf(activeVariant).toEqualTypeOf<"Hello" | "Bonjour" | "Hola">();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Import 'expectTypeOf' Function for Type Assertions

The expectTypeOf function is used for type assertions but is not imported in the test file. Ensure that you import it from the appropriate testing library.

Add this import at the top of the file:

+import { expectTypeOf } from 'vitest';

Also applies to: 317-317, 401-401, 410-410, 439-439, 470-470

@@ -0,0 +1,493 @@
import { waitFor } from "@testing-library/react";
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use Vue Testing Library Instead of React Testing Library

Since this is a Vue application, importing waitFor from @testing-library/react is incorrect. Please replace it with the Vue equivalent.

Apply this fix:

-import { waitFor } from "@testing-library/react";
+import { waitFor } from "@testing-library/vue";
📝 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.

Suggested change
import { waitFor } from "@testing-library/react";
import { waitFor } from "@testing-library/vue";

});

it("uses the devOverrides", () => {
process.env.NODE_ENV = "development";
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid Directly Mutating 'process.env.NODE_ENV'

Directly modifying process.env.NODE_ENV can have unintended side effects on other tests. Consider using a mocking utility or properly resetting the environment variable after the test.

Refactor as follows:

- process.env.NODE_ENV = "development";
+ const originalEnv = process.env.NODE_ENV;
+ process.env.NODE_ENV = "development";
+ // ... test code ...
+ process.env.NODE_ENV = originalEnv;

Alternatively, use vi.stubEnv if available.

Committable suggestion skipped: line range outside the PR's diff.

@asd55667 asd55667 closed this Nov 11, 2024
@asd55667 asd55667 reopened this Nov 11, 2024
@asd55667
Copy link
Author

/claim #68

@asd55667
Copy link
Author

it's also my first time to do algora's bounty. I forgot to claim when submitted, should i do another pull reuqest agian ?

@cstrnt
Copy link
Member

cstrnt commented Nov 23, 2024

Hey @asd55667 That might be a good idea. I am not sure If I can give you the reward right now since there is still a claim in process. Let me check!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants