Skip to content

Conversation

sreichel
Copy link
Contributor

@sreichel sreichel commented Oct 5, 2025

Description (*)

Refactored all tests.

  • every admin page has now its own config file to have a more clean structure
  • all admin pages have all buttons (save, delete, back, ... configured for easy access
  • all admin pages have entry points for common actions
    • view index page
    • edit an item
    • add new item

Basic Validation

  • buttons ... all configured buttons have to exist (error on new or missing)
  • fields ... all configured input have to exist (NO error on new or missing)
  • grid ... configured grid has to exist
  • navigation ... top navigation has to be correctly set to active
  • url ... path match configuration
  • title .... title match configuration

Tests

... see test files ...

Current Work

  • complete configuration for writing tests easier
  • add more tests (base on issues)

How to use

  • install DDEV
  • install cypress-plugin
  • run ddev cypress-open -C .cypress.config.js (browser), or ddev cypress-run -C .cypress.config.js (cli)

Structure

Every page has a file for tests and a configuration file. E.g.

cypress/e2e/openmage/backend/cms/page.cy.js
const test = cy.testBackendCmsPage.config;
const validation = cy.openmage.validation;

describe(`Checks admin system "${test.index.title}"`, () => {
  beforeEach('Log in the user', () => {
      cy.adminLogIn();
      cy.adminGoToTestRoute(test, test.index);
  });

  it(`tests index route`, () => {
      validation.pageElements(test, test.index);
  });

  it(`tests edit route`, () => {
      test.index.clickGridRow();
      validation.pageElements(test, test.edit);
  });

  it(`tests new route`, () => {
      test.index.clickAdd();
      validation.pageElements(test, test.new);
  });

  it('tests to disable a CMS page that is used in config', () => {
      test.index.clickGridRow();

      test.edit.disablePage();
      test.edit.clickSaveAndContinue();

      validation.hasWarningMessage('Cannot disable page, it is used in configuration');
      validation.hasSuccessMessage('The page has been saved.');

      cy.get('#messages').screenshot('error-disable-active-page', { overwrite: true, padding: 10 });
  });

  it('tests to delete a CMS page that is used in config', () => {
      test.index.clickGridRow();
      test.edit.clickDelete();

      validation.hasErrorMessage('Cannot delete page');

      cy.get('#messages').screenshot('error-delete-active-page', { overwrite: true, padding: 10 });
  });

  it('tests to add a CMS page', () => {
      test.index.clickAdd();
      test.edit.clickSaveAndContinue();

      // @todo add validation for required fields
  });

  it('tests to un-asign a CMS page that is used in config', () => {
      test.index.clickGridRow();

      //cy.log('Asign another store to the CMS page');
      //cy.get('#page_store_id')
      //    .select(4);

      //tools.clickAction(test.edit.__buttons.saveAndContinue);

      // @todo: fix needed - this test passes because of a Magento bug
      //validation.hasSuccessMessage('The page has been saved.');

      test.edit.resetStores();
      test.edit.clickSaveAndContinue();

      validation.hasSuccessMessage('The page has been saved.');
  });
});
cypress/support/openmage/backend/cms/page.js
const tools = cy.openmage.tools;

// selector for all buttons
const base = {
  _button: '.form-buttons button',
};

// base configuration for input fields
base.__fields = {
  page_title : {
      selector: '#page_title',
  },
  // ... more fields ...
};

// base configuration for tabs
base.__tabs = {
  general: '#page_tabs_main_section',
  content: '#page_tabs_content_section',
  // ... more tabs ...

cy.testBackendCmsPage = {};

// configuration
cy.testBackendCmsPage.config = {
  // selector for top-navigation
  _id: '#nav-admin-cms-page',
  // selector for sub-navigation
  _id_parent: '#nav-admin-cms',
  // selector to get page title
  _h3: 'h3.icon-head',
  // import: mandatory when "__button" is used in pages
  _button: base._button,
  // helper to click tab
  clickTabMain: () => {
      tools.click(base.__tabs.general, 'Clicking on General tab');
  },
  // ... more ...
}

// configuration for index action
cy.testBackendCmsPage.config.index = {
  // validate title
  title: 'Manage Pages',
  // validate url
  url: 'cms_page/index',
  // validate grid
  _grid: '#cmsPageGrid',
  // configure and validate buttons
  __buttons: {
      add: base._button + '[title="Add New Page"]',
  },
  // helper to click add button
  clickAdd: () => {
      tools.click(cy.testBackendCmsPage.config.index.__buttons.add);
  },
  // helper to click row element
  clickGridRow: (selector = 'td', content = 'no-route') => {
      tools.clickContains(cy.testBackendCmsPage.config.index._grid, selector, content, 'Select a CMS page');
  },
}

// configuration for edit action
cy.testBackendCmsPage.config.edit = {
  // validate title
  title: 'Edit Page',
  // validate url
  url: 'cms_page/edit',
  // configure and validate buttons
  __buttons: {
      save: base._button + '[title="Save Page"]',
      saveAndContinue: base._button + '[title="Save and Continue Edit"]',
      delete: base._button + '[title="Delete Page"]',
      back: base._button + '[title="Back"]',
      reset: base._button + '[title="Reset"]',
  },
  // import base configuration
  __fields: base.__fields,
  __tabs: base.__tabs,
  // helper for repeating actions etc
  disablePage: () => {
      cy.log('Disable the CMS page');
      cy.get(base.__fields.page_is_active.selector)
          .select('Disabled');
  },
  // ... more ...
}

// ... more routes ...

@github-actions github-actions bot added Template : admin Relates to admin template Component: Adminhtml Relates to Mage_Adminhtml Component: Newsletter Relates to Mage_Newsletter labels Oct 5, 2025
@sreichel sreichel marked this pull request as ready for review October 5, 2025 20:50
@Copilot Copilot AI review requested due to automatic review settings October 5, 2025 20:50
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Refactors Cypress end-to-end tests by modularizing route definitions, introducing shared helpers, and updating tests to the new structure.

  • Split monolithic route config into granular backend/ frontend path modules.
  • Added reusable helpers for page checks, clicks, and message assertions; updated tests to use them.
  • Minor admin template improvement: added title attribute to “Add New Template” button.

Reviewed Changes

Copilot reviewed 55 out of 55 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
cypress/support/openmage/frontend/paths.js New frontend route map (replaces frontend part of old config).
cypress/support/openmage/config/paths.js Removed monolithic routes file; functionality split across backend/frontend modules.
cypress/support/openmage/backend/system.js New modular system routes (cache, design, email, myaccount, indexes, stores, variables, config).
cypress/support/openmage/backend/sales.js New modular sales routes (credit memo, invoice, order, shipment, transactions).
cypress/support/openmage/backend/promo.js New modular promo routes (catalog rules, quote rules).
cypress/support/openmage/backend/newsletter.js New modular newsletter routes (templates, queue, subscribers, reports).
cypress/support/openmage/backend/dashboard.js New dashboard route module.
cypress/support/openmage/backend/customer.js New customer routes (customers, groups, online).
cypress/support/openmage/backend/cms.js New CMS routes (blocks, pages, widgets) plus CMS-specific helpers.
cypress/support/openmage/backend/catalog.js New catalog routes (products, categories, search, sitemap, URL rewrite).
cypress/support/openmage.js Added utilities: check.pageElements, tools.clickAction/clickGridRow, message helpers; removed validation.saveAction.
cypress/support/e2e.js Switched imports to new modular backend/ frontend paths.
cypress/support/commands.js Updated adminGoToTestRoute signature; deprecated adminTestRoute; minor behavior changes.
cypress/fixtures/example.json Added sample fixture data.
cypress/e2e/... (many backend tests) Updated tests to use new route objects and helpers; added index/edit/new route coverage per area.
cypress/e2e/openmage/frontend/newsletter-subscribe.cy.js Updated to use new helpers and frontend path map.
cypress/e2e/openmage/frontend/customer/account/create.cy.js Updated to use new helpers and message assertions.
app/design/adminhtml/default/default/template/newsletter/template/list.phtml Added title attribute to "Add New Template" button for better UX and test targeting.

@sreichel sreichel requested a review from Copilot October 7, 2025 08:37
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 84 out of 84 changed files in this pull request and generated 11 comments.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 84 out of 84 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

cypress/support/openmage.js:1

  • validateFields builds the advice selector using fields[field].css, but fields[field] is a selector string; this results in '#advice-undefined-'. Use validation.css instead to correctly target the validation message.
cy.openmage = {};

Comment on lines +1 to +3
const base = {
_button: '.form-buttons button'
}
Copy link
Preview

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

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

[nitpick] The _button selector constant is duplicated across many support files. Extract a shared selector (e.g., cy.openmage.selectors.baseButton or a common module) to avoid drift and simplify future updates.

Copilot uses AI. Check for mistakes.

@sreichel sreichel requested a review from Copilot October 7, 2025 09:08
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 84 out of 84 changed files in this pull request and generated 4 comments.

Comment on lines +23 to +27
cy.get(test._button).filter(':visible').should('have.length', Object.keys(path.__buttons).length);

for (const button of Object.keys(path.__buttons)) {
cy.get(path.__buttons[button]).should('exist');
};
Copy link
Preview

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

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

Asserting the exact count of visible buttons can be brittle when themes/extensions add buttons. Recommend removing the length assertion and only asserting the presence of each configured button to avoid false negatives.

Copilot uses AI. Check for mistakes.

Copy link

sonarqubecloud bot commented Oct 7, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
15.1% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@sreichel sreichel requested a review from Copilot October 7, 2025 09:42
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 84 out of 84 changed files in this pull request and generated 3 comments.

Comment on lines +68 to +74
click: (selector, log = 'Clicking on something') => {
cy.log(log);
cy.get(selector).first().click({force: true, multiple: false});
},
clickContains: (element, selector, content, log = 'Clicking on some content') => {
cy.log(log);
cy.get(element).contains(selector, content).first().click({force: true, multiple: false});
Copy link
Preview

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

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

Both click helpers default to force: true, which can mask visibility/overlap issues and make tests flaky. Consider removing force by default, adding a wait for visibility (e.g., .should('be.visible')), or allowing force to be an explicit optional parameter to these helpers.

Suggested change
click: (selector, log = 'Clicking on something') => {
cy.log(log);
cy.get(selector).first().click({force: true, multiple: false});
},
clickContains: (element, selector, content, log = 'Clicking on some content') => {
cy.log(log);
cy.get(element).contains(selector, content).first().click({force: true, multiple: false});
click: (selector, log = 'Clicking on something', force = false) => {
cy.log(log);
cy.get(selector).first().should('be.visible').click({force, multiple: false});
},
clickContains: (element, selector, content, log = 'Clicking on some content', force = false) => {
cy.log(log);
cy.get(element).contains(selector, content).first().should('be.visible').click({force, multiple: false});

Copilot uses AI. Check for mistakes.

Comment on lines +19 to 29
cy.openmage.check = {
buttons: (test, path, log = 'Checking for existing buttons') => {
cy.log(log);
if (path.__buttons !== undefined) {
cy.get(test._button).filter(':visible').should('have.length', Object.keys(path.__buttons).length);

for (const button of Object.keys(path.__buttons)) {
cy.get(path.__buttons[button]).should('exist');
};
}
},
Copy link
Preview

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

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

The exact count assertion on visible buttons is brittle and may fail when the UI renders extra action buttons (e.g., from extensions or additional core actions). Since you already assert existence for each configured selector below, consider dropping the length check or relaxing it (e.g., >=) to avoid false negatives.

Copilot uses AI. Check for mistakes.

Comment on lines +1 to +3
const base = {
_button: '.form-buttons button',
}
Copy link
Preview

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

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

[nitpick] The base pattern (const base = { _button: '...' }) is duplicated across many support modules. Extracting a shared base (e.g., support/openmage/base.js) and importing it would reduce duplication and keep selectors consistent across pages.

Suggested change
const base = {
_button: '.form-buttons button',
}
import { base } from '../../base.js';

Copilot uses AI. Check for mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Adminhtml Relates to Mage_Adminhtml Component: Newsletter Relates to Mage_Newsletter improvement Template : admin Relates to admin template
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant