Setting Up Cypress Tests for 1C-Bitrix
Cypress is a more modern alternative to Selenium for E2E frontend testing on 1C-Bitrix sites. The key advantage: tests run inside the browser, have full access to the DOM and network, and automatically wait for elements to appear. Cypress has fewer flaky tests ("sometimes fails, sometimes not") than Selenium because there is no race condition with explicit sleep() calls.
Setting Up Cypress Tests for 1C-Bitrix
Installation and Structure
Cypress is installed as a dev dependency in the template folder or in the project root:
npm install --save-dev cypress
Test structure for a 1C-Bitrix project:
cypress/
e2e/
catalog/
filter.cy.ts
product-card.cy.ts
cart/
add-to-cart.cy.ts
checkout.cy.ts
auth/
login.cy.ts
support/
commands.ts <- custom commands
e2e.ts <- global imports
fixtures/
user.json <- test data
product.json
cypress.config.ts
cypress.config.ts for 1C-Bitrix
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
baseUrl: 'https://test.site.ru',
specPattern: 'cypress/e2e/**/*.cy.ts',
supportFile: 'cypress/support/e2e.ts',
viewportWidth: 1280,
viewportHeight: 900,
defaultCommandTimeout: 8000,
requestTimeout: 10000,
video: false,
screenshotOnRunFailure: true,
// Settings for Bitrix — sessions and CSRF
experimentalModifyObstructiveThirdPartyCode: true,
},
env: {
adminLogin: 'admin',
adminPassword: '', // from environment variable CYPRESS_adminPassword
siteSessid: '', // CSRF token for API requests
},
});
Custom Commands for 1C-Bitrix
// cypress/support/commands.ts
declare global {
namespace Cypress {
interface Chainable {
loginBitrix(login: string, password: string): Chainable<void>;
addToCart(productUrl: string): Chainable<void>;
getBitrixSessid(): Chainable<string>;
}
}
}
Cypress.Commands.add('loginBitrix', (login, password) => {
cy.visit('/');
// Get sessid from cookie
cy.getCookie('PHPSESSID').then(() => {
cy.request({
method: 'POST',
url: '/local/ajax/auth.php',
body: { action: 'login', login, password },
}).then(resp => {
expect(resp.body.status).to.eq('success');
});
});
});
Cypress.Commands.add('addToCart', (productUrl) => {
cy.visit(productUrl);
cy.get('[data-action="add-to-cart"]').click();
// Wait for cart counter to update
cy.get('.cart-counter', { timeout: 5000 }).should('not.have.text', '0');
});
E2E Test for the Catalog Filter
// cypress/e2e/catalog/filter.cy.ts
describe('Smart catalog filter', () => {
beforeEach(() => {
cy.visit('/catalog/tools/');
// Wait for filter and products to load
cy.get('.catalog-filter').should('be.visible');
cy.get('.product-list').should('be.visible');
});
it('filters products by brand', () => {
cy.get('[data-filter-prop="BRAND"] [value="bosch"]').click();
// Wait for AJAX update (loader disappears)
cy.get('.catalog-loading').should('not.exist');
// URL must change
cy.url().should('include', 'brand=bosch');
// All cards contain the Bosch brand
cy.get('.product-brand').each($el => {
cy.wrap($el).should('have.text', 'Bosch');
});
});
it('resets the filter', () => {
cy.get('[data-filter-prop="BRAND"] [value="bosch"]').click();
cy.get('.catalog-loading').should('not.exist');
cy.get('.filter-reset-btn').click();
cy.get('.catalog-loading').should('not.exist');
cy.url().should('not.include', 'brand=bosch');
});
it('displays the correct product count in the filter counter', () => {
// Verify the counter updates when the filter changes
cy.get('[data-filter-prop="BRAND"] [value="makita"]').click();
cy.get('.catalog-loading').should('not.exist');
cy.get('.products-count').invoke('text').then(text => {
const count = parseInt(text.replace(/\D/g, ''));
cy.get('.product-card').should('have.length', Math.min(count, 24)); // 24 — pageSize
});
});
});
Order Form Test
// cypress/e2e/cart/checkout.cy.ts
describe('Order checkout', () => {
it('successfully places an order as a guest', () => {
// Add product to cart via UI
cy.addToCart('/catalog/tools/drills/bosch-gsh/');
cy.visit('/cart/');
cy.get('.checkout-btn').click();
// Fill in the order form
cy.get('#ORDER_PROP_1').type('Ivan Ivanov'); // Name
cy.get('#ORDER_PROP_2').type('[email protected]'); // Email
cy.get('#ORDER_PROP_3').type('+79001234567'); // Phone
cy.get('#ORDER_PROP_6').type('Moscow, Test Street, 1'); // Address
// Select delivery
cy.get('[name="DELIVERY_ID"][value="1"]').click();
// Select payment method
cy.get('[name="PAY_SYSTEM_ID"][value="1"]').click();
// Accept user agreement
cy.get('#agree').check();
// Submit order
cy.get('.order-submit-btn').click();
// Wait for order success page
cy.url({ timeout: 15000 }).should('include', '/personal/order/');
cy.get('.order-success-message').should('be.visible');
});
});
Intercepting AJAX Requests to 1C-Bitrix
// Mocking an AJAX response for isolated testing
cy.intercept('POST', '/local/ajax/cart.php', {
statusCode: 200,
body: {
status: 'success',
cart: { items: [], totalCount: 0, totalPrice: 0 },
},
}).as('cartRequest');
cy.get('[data-action="add-to-cart"]').click();
cy.wait('@cartRequest').its('response.statusCode').should('eq', 200);
Timelines
| Task | Timeline |
|---|---|
| Install Cypress, base configuration, custom commands | 4–8 hours |
| E2E tests for critical scenarios (5–10 tests) | 1–2 days |
| Full test suite: catalog + cart + checkout | 2–4 days |
| Integration with GitHub Actions / GitLab CI | 4–8 hours |







