diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index d3e6edc..350c837 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -48,7 +48,9 @@ jobs: - name: Run Playwright tests run: npx playwright test - - uses: actions/upload-artifact@v4 + - name: Upload artifacts + uses: actions/upload-artifact@v4 + if: always() with: name: playwright-report path: playwright-report/ diff --git a/.gitignore b/.gitignore index ff456c1..20f8030 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ yarn-error.log .phpunit.result.cache .DS_Store testingdb -.vscode .env .auth/ artifacts/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..bfd59dd --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "shevaua.phpcs", + "sbenp.prettier-vscode" + ], +} \ No newline at end of file diff --git a/README.md b/README.md index f8a6206..3e368f9 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ WordPress Feature flags plugin allow developers to configure features in plugins ### PHP filters -#### `mr_feature_flags_max_allowed` +#### `codeb_feature_flags_max_allowed` Filter to define the maximum number of allowed flags. It is recommended to keep this to default value, which is 20. @@ -18,7 +18,7 @@ Example usage: ```php add_filter( - 'mr_feature_flags_max_allowed', + 'codeb_feature_flags_max_allowed', static function () { return 10; } @@ -27,16 +27,20 @@ add_filter( ### JS filters -##### `mrFeatureFlags.newFlag.defaultStatus` +##### `codebFeatureFlags.newFlag.defaultStatus` The filter controls whether the new flag is enabled by default or not. Default `true` Example usage: ```js -addFilter('mrFeatureFlags.newFlag.defaultStatus', 'codeb-feature-flags', () => { - return false; -}); +addFilter( + 'codebFeatureFlags.newFlag.defaultStatus', + 'codeb-feature-flags', + () => { + return false; + } +); ``` ## Development setup @@ -51,27 +55,33 @@ JS setup - `yarn install` - `yarn build` to create the build -- `yarn start` to start the development watch mode +- `yarn start` to start the watch mode + +### wp-env + +This plugin uses `wp-env` setup to for local environment. + +- `wp-env start` to start the containers +- `wp-env stop` to stop the containers + +More details on how to access local environment can be found [here](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/#quick-tldr-instructions). ## Linting and formatting PHP - `composer lint` -- To auto fix the linting errors `composer lint:fix` - -💡 [VSCode extension](https://marketplace.visualstudio.com/items?itemName=shevaua.phpcs) to auto format PHP files based on `phpcs.xml.dist` configuration +- `composer lint:fix` to auto fix PHP linting errors. JS - `yarn lint:js` - -💡 [VSCode extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to auto format JS / TS files based on `.prettierrc.js` configuration +- `yarn lint:js:fix` to auto fix JS linting errors. CSS - `yarn lint:css` -- To auto fix the css linting errors `yarn lint:css:fix` +- `yarn lint:css:fix` to auto fix CSS linting errors. ## Testing @@ -85,10 +95,10 @@ CSS ### JS -- Run `yarn test:js` which will run all jest and React Testing Library tests +- Run `yarn test:js` to run all Jest and React Testing Library tests ### E2E The E2E tests depends on `wp-env` setup. Ensure you run `wp-env start` before running the tests. -- Run `yarn test:e2e` which will run all Playwright e2e tests. +- Run `yarn test:e2e` to run all Playwright e2e tests. diff --git a/includes/Api/Flags.php b/includes/Api/Flags.php index 7a8cb8e..192f7da 100644 --- a/includes/Api/Flags.php +++ b/includes/Api/Flags.php @@ -13,6 +13,7 @@ use WP_Error; use WP_REST_Server; use WP_REST_Request; +use CodeB\FeatureFlags\Flag; /** * Class Settings @@ -22,13 +23,6 @@ */ class Flags { - /** - * Name in options table. - * - * @var string $option_name - */ - public static $option_name = 'mr_feature_flags'; - /** * Maximum allowed flags. * @@ -83,7 +77,7 @@ public function register_routes(): void { * @return mixed List of flags. */ public function get_all_flags() { - $flags = get_option( self::$option_name, [] ); + $flags = get_option( Flag::$option_name, [] ); return rest_ensure_response( $flags ); } @@ -102,14 +96,14 @@ public function post_flags( WP_REST_Request $request ) { /** * Filter to update max allowed feature flags. */ - $max_allowed_flags = apply_filters( 'mr_feature_flags_max_allowed', self::$max_flags ); + $max_allowed_flags = apply_filters( 'codeb_feature_flags_max_allowed', self::$max_flags ); if ( count( $input_data['flags'] ) > $max_allowed_flags ) { // translators: %d is a placeholder for the maximum allowed flags. $error_message = sprintf( __( 'Cannot add more than %d flags', 'codeb-feature-flags' ), $max_allowed_flags ); return new WP_Error( 'flag_limit_exceeded', $error_message, array( 'status' => 400 ) ); } - update_option( self::$option_name, $input_data['flags'] ); + update_option( Flag::$option_name, $input_data['flags'] ); return rest_ensure_response( array( 'status' => 200, diff --git a/includes/Flag.php b/includes/Flag.php index 86da8f4..d4042f3 100644 --- a/includes/Flag.php +++ b/includes/Flag.php @@ -23,7 +23,7 @@ class Flag { * * @var string $option_name */ - public static $option_name = 'mr_feature_flags'; + public static $option_name = 'codeb_feature_flags'; /** diff --git a/includes/Helper.php b/includes/Helper.php index db30568..91a0383 100644 --- a/includes/Helper.php +++ b/includes/Helper.php @@ -1,6 +1,6 @@ '; + echo '
'; } } diff --git a/package.json b/package.json index 4473db4..4930db2 100644 --- a/package.json +++ b/package.json @@ -1,56 +1,60 @@ { - "name": "codeb-feature-flags", - "version": "0.2.1", - "description": "Allows developers to enable / disable features based on flags.", - "scripts": { - "start": "wp-scripts start", - "build": "wp-scripts build", - "lint:js": "wp-scripts lint-js", - "lint:css": "wp-scripts lint-style", - "lint:css:fix": "npm run lint:css -- --fix", - "test:js": "wp-scripts test-unit-js", - "test:watch": "wp-scripts test-unit-js --watch", - "prepare": "husky", - "wp-env": "wp-env start", - "test:e2e": "npx playwright test --reporter=list" - }, - "devDependencies": { - "@playwright/test": "^1.42.0", - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "14.2.1", - "@types/jest": "^29.5.12", - "@types/node": "^20.11.20", - "@types/react-syntax-highlighter": "^15.5.11", - "@types/wordpress__components": "^23.0.11", - "@wordpress/e2e-test-utils-playwright": "^0.20.0", - "@wordpress/env": "^9.4.0", - "@wordpress/eslint-plugin": "^17.9.0", - "@wordpress/scripts": "^27.3.0", - "eslint": "^8.57.0", - "eslint-import-resolver-alias": "^1.1.2", - "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-import": "^2.29.1", - "husky": "^9.0.11", - "jest-environment-jsdom": "^29.7.0", - "prettier": "^3.2.5" - }, - "keywords": [], - "author": "Mohan Raj ", - "license": "ISC", - "dependencies": { - "@wordpress/api-fetch": "^6.48.0", - "@wordpress/components": "^27.0.0", - "@wordpress/data": "^9.22.0", - "@wordpress/dom-ready": "^3.52.0", - "@wordpress/hooks": "^3.52.0", - "@wordpress/i18n": "^4.52.0", - "@wordpress/notices": "^4.20.0", - "dotenv": "^16.4.5", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-syntax-highlighter": "^15.5.0", - "react-test-renderer": "^18.2.0", - "ts-loader": "^9.5.1", - "typescript": "^5.3.3" - } -} + "name": "codeb-feature-flags", + "version": "0.3.0", + "description": "Allows developers to enable / disable features based on flags.", + "license": "ISC", + "author": "Mohan Raj ", + "scripts": { + "build": "wp-scripts build", + "lint:css": "wp-scripts lint-style", + "lint:css:fix": "npm run lint:css -- --fix", + "lint:js": "wp-scripts lint-js", + "lint:js:fix": "wp-scripts lint-js --fix", + "prepare": "husky", + "start": "wp-scripts start", + "test:e2e": "npx playwright test --reporter=list", + "test:js": "wp-scripts test-unit-js", + "test:watch": "wp-scripts test-unit-js --watch", + "version:major": "node ./scripts/version major", + "version:minor": "node ./scripts/version minor", + "version:patch": "node ./scripts/version patch", + "wp-env": "wp-env start" + }, + "dependencies": { + "@wordpress/api-fetch": "^6.48.0", + "@wordpress/components": "^27.0.0", + "@wordpress/data": "^9.22.0", + "@wordpress/dom-ready": "^3.52.0", + "@wordpress/hooks": "^3.52.0", + "@wordpress/i18n": "^4.52.0", + "@wordpress/notices": "^4.20.0", + "dotenv": "^16.4.5", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-syntax-highlighter": "^15.5.0", + "react-test-renderer": "^18.2.0", + "ts-loader": "^9.5.1", + "typescript": "^5.3.3" + }, + "devDependencies": { + "@playwright/test": "^1.42.0", + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/react": "14.2.1", + "@types/jest": "^29.5.12", + "@types/node": "^20.11.20", + "@types/react-syntax-highlighter": "^15.5.11", + "@types/wordpress__components": "^23.0.11", + "@wordpress/e2e-test-utils-playwright": "^0.20.0", + "@wordpress/env": "^9.4.0", + "@wordpress/eslint-plugin": "^17.9.0", + "@wordpress/scripts": "^27.3.0", + "eslint": "^8.57.0", + "eslint-import-resolver-alias": "^1.1.2", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-import": "^2.29.1", + "husky": "^9.0.11", + "jest-environment-jsdom": "^29.7.0", + "prettier": "^3.2.5" + }, + "keywords": [] +} \ No newline at end of file diff --git a/playwright.config.ts b/playwright.config.ts index ee4c2fc..cd5dc73 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -12,7 +12,7 @@ export default defineConfig({ fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, - workers: 4, + workers: process.env.CI ? 4 : 1, reporter: 'html', use: { baseURL: process.env.WP_BASE_URL, diff --git a/plugin.php b/plugin.php index 5abc085..3b4e936 100644 --- a/plugin.php +++ b/plugin.php @@ -9,7 +9,7 @@ * Plugin Name: Feature Flags * Plugin URI: https://github.com/codebtech/wp-feature-flags * Description: Allows developers to enable / disable features based on flags. - * Version: 0.2.1 + * Version: 0.3.0 * Requires at least: 6.4 * Requires PHP: 8.1 * Author: Mohan Raj @@ -33,7 +33,7 @@ /** * API and Plugin version constants. */ -define( 'MR_FEATURE_FLAGS_PLUGIN_PATH', __FILE__ ); +define( 'CODEB_FEATURE_FLAGS_PLUGIN_PATH', __FILE__ ); if ( ! file_exists( Flag::class ) ) { include_once __DIR__ . '/vendor/autoload.php'; @@ -44,7 +44,7 @@ 'admin_enqueue_scripts', static function ( string $page ): void { if ( 'toplevel_page_codeb-feature-flags' === $page ) { - mr_feature_flags_load_settings_scripts(); + codeb_feature_flags_load_settings_scripts(); } } ); @@ -54,10 +54,10 @@ static function ( string $page ): void { * * @return void */ -function mr_feature_flags_load_settings_scripts(): void { +function codeb_feature_flags_load_settings_scripts(): void { - $plugin_url = plugin_dir_url( MR_FEATURE_FLAGS_PLUGIN_PATH ); - $settings_asset_file = require_once plugin_dir_path( MR_FEATURE_FLAGS_PLUGIN_PATH ) . 'build/settings.asset.php'; // @phpcs:ignore + $plugin_url = plugin_dir_url( CODEB_FEATURE_FLAGS_PLUGIN_PATH ); + $settings_asset_file = require_once plugin_dir_path( CODEB_FEATURE_FLAGS_PLUGIN_PATH ) . 'build/settings.asset.php'; // @phpcs:ignore wp_enqueue_script( 'codeb-feature-flags', @@ -80,21 +80,21 @@ function mr_feature_flags_load_settings_scripts(): void { // Enqueue scripts and styles for front end. add_action( 'wp_enqueue_scripts', - __NAMESPACE__ . '\mr_feature_flags_scripts_enqueue' + __NAMESPACE__ . '\codeb_feature_flags_scripts_enqueue' ); // Enqueue scripts and styles for wp-admin. add_action( 'admin_enqueue_scripts', - __NAMESPACE__ . '\mr_feature_flags_scripts_enqueue' + __NAMESPACE__ . '\codeb_feature_flags_scripts_enqueue' ); /** * Enqueue scripts and assets for admin and front end */ -function mr_feature_flags_scripts_enqueue(): void { - $plugin_url = plugin_dir_url( MR_FEATURE_FLAGS_PLUGIN_PATH ); - $script_asset_file = include_once plugin_dir_path( MR_FEATURE_FLAGS_PLUGIN_PATH ) . 'build/index.asset.php'; +function codeb_feature_flags_scripts_enqueue(): void { + $plugin_url = plugin_dir_url( CODEB_FEATURE_FLAGS_PLUGIN_PATH ); + $script_asset_file = include_once plugin_dir_path( CODEB_FEATURE_FLAGS_PLUGIN_PATH ) . 'build/index.asset.php'; wp_enqueue_script( 'codeb-feature-flags-script', @@ -114,7 +114,7 @@ function mr_feature_flags_scripts_enqueue(): void { wp_localize_script( 'codeb-feature-flags-script', - 'mrFeatureFlags', + 'codebFeatureFlags', [ 'flags' => $flags_list, ] @@ -122,12 +122,12 @@ function mr_feature_flags_scripts_enqueue(): void { } // Registers feature flags admin setting page. -$mr_feature_flags_admin_settings = new Settings(); -$mr_feature_flags_admin_settings->register_feature_settings(); +$codeb_feature_flags_admin_settings = new Settings(); +$codeb_feature_flags_admin_settings->register_feature_settings(); // Registers feature flags API's. -$mr_feature_flags_register_api = new Flags(); -$mr_feature_flags_register_api->register(); +$codeb_feature_flags_register_api = new Flags(); +$codeb_feature_flags_register_api->register(); // Displays setting page link in plugin page. @@ -152,13 +152,13 @@ static function ( $links ) { } ); -register_deactivation_hook( __FILE__, __NAMESPACE__ . '\mr_feature_flags_uninstall' ); +register_deactivation_hook( __FILE__, __NAMESPACE__ . '\codeb_feature_flags_uninstall' ); /** * Uninstall method for the plugin. * * @return void */ -function mr_feature_flags_uninstall(): void { +function codeb_feature_flags_uninstall(): void { delete_option( Flag::$option_name ); } diff --git a/scripts/version.js b/scripts/version.js new file mode 100644 index 0000000..79f5211 --- /dev/null +++ b/scripts/version.js @@ -0,0 +1,65 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require('fs'); +const path = require('path'); +const package = require('../package.json'); + +const packagePath = path.join(process.cwd(), 'package.json'); +const phpPath = path.join(process.cwd(), 'plugin.php'); + +const bumpTypes = ['patch', 'minor', 'major']; + +const fsOpts = { encoding: 'utf-8' }; + +const getNewVersion = () => { + const bumpType = process.argv[2]; + let [major, minor, patch] = package.version + .split('.') + .map((num) => parseInt(num, 10)); + + if (!bumpTypes.includes(bumpType)) { + throw new Error(`Invalid bump type: ${bumpType}`); + } + + if (bumpType === 'patch') { + patch += 1; + } + + if (bumpType === 'minor') { + patch = 0; + minor += 1; + } + + if (bumpType === 'major') { + patch = 0; + minor = 0; + major += 1; + } + + return `${major}.${minor}.${patch}`; +}; + +(async () => { + const previousVersion = package.version; + const newVersion = getNewVersion(); + + const newPackage = JSON.stringify( + { + ...package, + version: newVersion, + }, + null, + 2 + ); + + const [php] = await Promise.all([fs.promises.readFile(phpPath, fsOpts)]); + + const newPHP = php.replace(new RegExp(previousVersion, 'g'), newVersion); + + await Promise.all([ + fs.promises.writeFile(packagePath, newPackage, fsOpts), + fs.promises.writeFile(phpPath, newPHP, fsOpts), + ]); + + // eslint-disable-next-line no-console + console.log(`Version bumped to: ${newVersion}`); +})(); diff --git a/src/components/Flags.tsx b/src/components/Flags.tsx index 39afc29..1cddc14 100644 --- a/src/components/Flags.tsx +++ b/src/components/Flags.tsx @@ -81,7 +81,7 @@ const Layout = (): JSX.Element => { return ( <>
-

{__('Feature Flags settings', 'codeb-feature-flags')}

+

{__('Feature Flags', 'codeb-feature-flags')}

{lastFlag ?
: ''} {isLoading ? ( diff --git a/src/components/SubmitControls.tsx b/src/components/SubmitControls.tsx index e905c20..516c491 100644 --- a/src/components/SubmitControls.tsx +++ b/src/components/SubmitControls.tsx @@ -23,7 +23,7 @@ const SubmitControls = ({ }: SubmitControlsProps): JSX.Element => { const handleNewFlag = () => { const defaultStatus = applyFilters( - 'mrFeatureFlags.newFlag.defaultStatus', + 'codebFeatureFlags.newFlag.defaultStatus', true ) as boolean; const newFlag = { diff --git a/src/components/snippets/JsSnippet.tsx b/src/components/snippets/JsSnippet.tsx index 377ead3..1e222b9 100644 --- a/src/components/snippets/JsSnippet.tsx +++ b/src/components/snippets/JsSnippet.tsx @@ -8,8 +8,8 @@ export default function ({ flag }: { flag: string }): JSX.Element { return `import domReady from '@wordpress/dom-ready'; domReady(function () { if ( - typeof window?.mrFeatureFlags !== 'undefined' && - window.mrFeatureFlags.isEnabled('${flag}') + typeof window?.codebFeatureFlags !== 'undefined' && + window.codebFeatureFlags.isEnabled('${flag}') ) { // js code goes here... } diff --git a/src/components/snippets/TsSupport.tsx b/src/components/snippets/TsSupport.tsx index bfc51e6..411dc14 100644 --- a/src/components/snippets/TsSupport.tsx +++ b/src/components/snippets/TsSupport.tsx @@ -6,14 +6,14 @@ import Snippet from './Snippet'; const TsSupport = (): JSX.Element => { const tsSnippet = useMemo(() => { - return `declare namespace mrFeatureFlags { + return `declare namespace codebFeatureFlags { export interface FeatureFlagProps { isEnabled: (flag: string) => boolean; } } declare global { interface Window { - mrFeatureFlags: mrFeatureFlags.FeatureFlagProps; + codebFeatureFlags: codebFeatureFlags.FeatureFlagProps; } } export {};`; diff --git a/src/index.ts b/src/index.ts index 5f68277..9461583 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ -const { mrFeatureFlags } = window; +const { codebFeatureFlags } = window; import { Flag } from '../types'; //Appends isEnabled method to global window object. -mrFeatureFlags.isEnabled = (flag: string) => { - const isFlagExist: Flag | undefined = mrFeatureFlags.flags.find( +codebFeatureFlags.isEnabled = (flag: string) => { + const isFlagExist: Flag | undefined = codebFeatureFlags.flags.find( (item: Flag) => { return item.name === flag && item.enabled === true; } diff --git a/src/settings.tsx b/src/settings.tsx index 799336d..49de202 100644 --- a/src/settings.tsx +++ b/src/settings.tsx @@ -1,6 +1,8 @@ import { createRoot } from '@wordpress/element'; import Flags from './components/Flags'; import './styles/settings.scss'; -const container = document.getElementById('mr_feature_flags_settings_screen'); +const container = document.getElementById( + 'codeb_feature_flags_settings_screen' +); const root = container && createRoot(container); root?.render(); diff --git a/tests/e2e/feature-flags.spec.ts b/tests/e2e/feature-flags.spec.ts index 918ebd4..0067559 100644 --- a/tests/e2e/feature-flags.spec.ts +++ b/tests/e2e/feature-flags.spec.ts @@ -7,7 +7,7 @@ import { DisableFlag, OpenSdkModal, SaveFlags, - deleteLastFlag, + deleteAllFlags, } from './helper'; // eslint-disable-next-line @@ -16,18 +16,14 @@ test.use({ storageState: process.env.WP_AUTH_STORAGE }); test.describe('Feature flags', () => { test.beforeEach(async ({ page, admin }) => { await admin.visitAdminPage('/'); - - //Find the feature flags in side menu await page.getByRole('link', { name: 'Feature Flags' }).click(); - - //Confirm the setting page header await expect( - page.getByRole('heading', { name: 'Feature Flags settings' }) + page.getByRole('heading', { name: 'Feature Flags' }) ).toBeVisible(); }); test.afterEach(async ({ page }) => { - await deleteLastFlag(page); + await deleteAllFlags(page); }); test('Create and save new flag successfully', async ({ page }) => { @@ -61,11 +57,9 @@ test.describe('Feature flags', () => { }); test('Check duplicate and invalid flag', async ({ page }) => { - //Create new flag await AddNewFlagAndFill(page, 'testDuplicate'); await SaveFlags(page); - //Confirm save success expect( await page.getByLabel('Dismiss this notice').innerText() ).toMatch(/Saved successfully!/); @@ -80,9 +74,6 @@ test.describe('Feature flags', () => { expect(page.getByText(ERROR_FLAG_INVALID)).toBeVisible(); expect(page.getByRole('button', { name: 'Save' })).toBeDisabled(); - //Delete the flag - await deleteLastFlag(page); - expect( await page.getByLabel('Dismiss this notice').innerText() ).toMatch(/Saved successfully!/); @@ -118,10 +109,9 @@ test.describe('Feature flags', () => { 'navigator.clipboard.readText()' ); expect(jsClipboardText).toContain( - `window.mrFeatureFlags.isEnabled('${flagName}')` + `window.codebFeatureFlags.isEnabled('${flagName}')` ); - //Close SDK modal await CloseSdkModal(page); }); }); diff --git a/tests/e2e/helper/index.ts b/tests/e2e/helper/index.ts index c81bc1d..d309384 100644 --- a/tests/e2e/helper/index.ts +++ b/tests/e2e/helper/index.ts @@ -10,12 +10,30 @@ export async function deleteLastFlag(page: Page) { .last() .getByLabel('Delete Flag') .click(); + await page.getByRole('button', { name: 'Yes' }).click(); }, { box: true } ); } +export async function deleteAllFlags(page: Page) { + await test.step( + 'Delete all flag', + async () => { + const count = await page + .locator('id=mr-feature-flag-item') + .getByLabel('Delete Flag') + .count(); + + if (count > 0) { + for (let i = 0; i < count; ++i) await deleteLastFlag(page); + } + }, + { box: true } + ); +} + export async function AddNewFlag(page: Page, text: string) { await test.step( 'Add new flag', diff --git a/tests/e2e/visual-comparison.spec.ts b/tests/e2e/visual-comparison.spec.ts new file mode 100644 index 0000000..c962640 --- /dev/null +++ b/tests/e2e/visual-comparison.spec.ts @@ -0,0 +1,67 @@ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; +import { + AddNewFlagAndFill, + CloseSdkModal, + DisableFlag, + OpenSdkModal, + SaveFlags, + deleteAllFlags, +} from './helper'; + +test.describe.configure({ mode: 'serial' }); + +test.describe('Visual tests', () => { + test.use({ storageState: process.env.WP_AUTH_STORAGE }); + + test.beforeEach(async ({ page, admin }) => { + await admin.visitAdminPage('/'); + await page.getByRole('link', { name: 'Feature Flags' }).click(); + }); + + test.afterEach(async ({ page }) => { + await deleteAllFlags(page); + }); + + test('Feature flags screen without flags', async ({ page }) => { + await expect(page).toHaveScreenshot('no-flags.png'); + }); + + test('Feature flags screen with some flags', async ({ page }) => { + await AddNewFlagAndFill(page, 'hello_test'); + await AddNewFlagAndFill(page, '123'); + await DisableFlag(page, true); + await AddNewFlagAndFill(page, 'healthCheck'); + + await SaveFlags(page); + await expect(page).toHaveScreenshot('some-flags.png'); + }); + + test('Toggle feature flag', async ({ page }) => { + await AddNewFlagAndFill(page, 'auth0'); + await DisableFlag(page, true); + await expect(page).toHaveScreenshot('flag-disabled.png'); + }); + + test('Delete flag modal', async ({ page }) => { + await AddNewFlagAndFill(page, 'helloWorld'); + + await page + .locator('id=mr-feature-flag-item') + .last() + .getByLabel('Delete Flag') + .click(); + + await expect(page).toHaveScreenshot('delete-flag-modal.png'); + + await page.getByRole('button', { name: 'Yes' }).click(); + }); + + test('SDK modal', async ({ page }) => { + await AddNewFlagAndFill(page, 'drag-drop'); + await OpenSdkModal(page); + + await expect(page).toHaveScreenshot('sdk-modal.png'); + + await CloseSdkModal(page); + }); +}); diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/delete-flag-modal-chromium-darwin.png b/tests/e2e/visual-comparison.spec.ts-snapshots/delete-flag-modal-chromium-darwin.png new file mode 100644 index 0000000..e7e8d1b Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/delete-flag-modal-chromium-darwin.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/delete-flag-modal-chromium-linux.png b/tests/e2e/visual-comparison.spec.ts-snapshots/delete-flag-modal-chromium-linux.png new file mode 100644 index 0000000..0db7277 Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/delete-flag-modal-chromium-linux.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/flag-disabled-chromium-darwin.png b/tests/e2e/visual-comparison.spec.ts-snapshots/flag-disabled-chromium-darwin.png new file mode 100644 index 0000000..468f3f4 Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/flag-disabled-chromium-darwin.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/flag-disabled-chromium-linux.png b/tests/e2e/visual-comparison.spec.ts-snapshots/flag-disabled-chromium-linux.png new file mode 100644 index 0000000..0a473a3 Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/flag-disabled-chromium-linux.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/no-flags-chromium-darwin.png b/tests/e2e/visual-comparison.spec.ts-snapshots/no-flags-chromium-darwin.png new file mode 100644 index 0000000..029d383 Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/no-flags-chromium-darwin.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/no-flags-chromium-linux.png b/tests/e2e/visual-comparison.spec.ts-snapshots/no-flags-chromium-linux.png new file mode 100644 index 0000000..a98dee9 Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/no-flags-chromium-linux.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/sdk-modal-chromium-darwin.png b/tests/e2e/visual-comparison.spec.ts-snapshots/sdk-modal-chromium-darwin.png new file mode 100644 index 0000000..fb6243a Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/sdk-modal-chromium-darwin.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/sdk-modal-chromium-linux.png b/tests/e2e/visual-comparison.spec.ts-snapshots/sdk-modal-chromium-linux.png new file mode 100644 index 0000000..3eb8a5b Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/sdk-modal-chromium-linux.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/some-flags-chromium-darwin.png b/tests/e2e/visual-comparison.spec.ts-snapshots/some-flags-chromium-darwin.png new file mode 100644 index 0000000..dd2411c Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/some-flags-chromium-darwin.png differ diff --git a/tests/e2e/visual-comparison.spec.ts-snapshots/some-flags-chromium-linux.png b/tests/e2e/visual-comparison.spec.ts-snapshots/some-flags-chromium-linux.png new file mode 100644 index 0000000..0649a60 Binary files /dev/null and b/tests/e2e/visual-comparison.spec.ts-snapshots/some-flags-chromium-linux.png differ diff --git a/tests/integration/FlagsApiTest.php b/tests/integration/FlagsApiTest.php index 21fc1c7..104203f 100644 --- a/tests/integration/FlagsApiTest.php +++ b/tests/integration/FlagsApiTest.php @@ -193,7 +193,7 @@ public function test_create_item_with_custom_max_allowed_filter() { // Mock the filter hook $mocked_max_flags = 3; - add_filter('mr_feature_flags_max_allowed', function () use ($mocked_max_flags) { + add_filter('codeb_feature_flags_max_allowed', function () use ($mocked_max_flags) { return $mocked_max_flags; }); diff --git a/tests/unit/SettingsTest.php b/tests/unit/SettingsTest.php index 2d029a7..5119474 100644 --- a/tests/unit/SettingsTest.php +++ b/tests/unit/SettingsTest.php @@ -57,6 +57,6 @@ public function testRenderPage() { $output = ob_get_clean(); - $this->assertStringContainsString('
', $output); + $this->assertStringContainsString('
', $output); } } diff --git a/types/window.d.ts b/types/window.d.ts index 29ce5d3..055ee35 100644 --- a/types/window.d.ts +++ b/types/window.d.ts @@ -12,7 +12,7 @@ declare namespace mrFeatureFlag { declare global { interface Window { - mrFeatureFlags: mrFeatureFlag.FeatureFlagProps; + codebFeatureFlags: mrFeatureFlag.FeatureFlagProps; } }