[FIX] website_sale_aplicoop: Remove redundant string= attributes and fix OCA linting warnings

- Remove redundant string= from 17 field definitions where name matches string value (W8113)
- Convert @staticmethod to instance methods in selection methods for proper self.env._() access
- Fix W8161 (prefer-env-translation) by using self.env._() instead of standalone _()
- Fix W8301/W8115 (translation-not-lazy) by proper placement of % interpolation outside self.env._()
- Remove unused imports of odoo._ from group_order.py and sale_order_extension.py
- All OCA linting warnings in website_sale_aplicoop main models are now resolved

Changes:
- website_sale_aplicoop/models/group_order.py: 21 field definitions cleaned
- website_sale_aplicoop/models/sale_order_extension.py: 5 field definitions cleaned + @staticmethod conversion
- Consistent with OCA standards for addon submission
This commit is contained in:
snt 2026-02-18 17:54:43 +01:00
parent 5c89795e30
commit 6fbc7b9456
73 changed files with 5386 additions and 4354 deletions

View file

@ -134,7 +134,7 @@ docker-compose exec odoo odoo -d odoo --test-enable --log-level=test --stop-afte
odoo.define('website_sale_aplicoop.test_my_feature', function (require) {
'use strict';
var QUnit = window.QUnit;
QUnit.module('website_sale_aplicoop.my_feature', {
beforeEach: function() {
// Setup code
@ -257,6 +257,6 @@ exit $exit_code
---
**Maintainer**: Criptomart
**License**: AGPL-3.0
**Maintainer**: Criptomart
**License**: AGPL-3.0
**Last Updated**: February 3, 2026

View file

@ -3,222 +3,273 @@
* Tests core cart functionality (add, remove, update, calculate)
*/
odoo.define('website_sale_aplicoop.test_cart_functions', function (require) {
'use strict';
odoo.define("website_sale_aplicoop.test_cart_functions", function (require) {
"use strict";
var QUnit = window.QUnit;
QUnit.module('website_sale_aplicoop', {
beforeEach: function() {
// Setup: Initialize groupOrderShop object
window.groupOrderShop = {
orderId: '1',
cart: {},
labels: {
'save_cart': 'Save Cart',
'reload_cart': 'Reload Cart',
'checkout': 'Checkout',
'confirm_order': 'Confirm Order',
'back_to_cart': 'Back to Cart'
}
};
// Clear localStorage
localStorage.clear();
QUnit.module(
"website_sale_aplicoop",
{
beforeEach: function () {
// Setup: Initialize groupOrderShop object
window.groupOrderShop = {
orderId: "1",
cart: {},
labels: {
save_cart: "Save Cart",
reload_cart: "Reload Cart",
checkout: "Checkout",
confirm_order: "Confirm Order",
back_to_cart: "Back to Cart",
},
};
// Clear localStorage
localStorage.clear();
},
afterEach: function () {
// Cleanup
localStorage.clear();
delete window.groupOrderShop;
},
},
afterEach: function() {
// Cleanup
localStorage.clear();
delete window.groupOrderShop;
function () {
QUnit.test("groupOrderShop object initializes correctly", function (assert) {
assert.expect(3);
assert.ok(window.groupOrderShop, "groupOrderShop object exists");
assert.equal(window.groupOrderShop.orderId, "1", "orderId is set");
assert.ok(typeof window.groupOrderShop.cart === "object", "cart is an object");
});
QUnit.test("cart starts empty", function (assert) {
assert.expect(1);
var cartKeys = Object.keys(window.groupOrderShop.cart);
assert.equal(cartKeys.length, 0, "cart has no items initially");
});
QUnit.test("can add item to cart", function (assert) {
assert.expect(4);
// Add a product to cart
var productId = "123";
var productData = {
name: "Test Product",
price: 10.5,
quantity: 2,
};
window.groupOrderShop.cart[productId] = productData;
assert.equal(Object.keys(window.groupOrderShop.cart).length, 1, "cart has 1 item");
assert.ok(window.groupOrderShop.cart[productId], "product exists in cart");
assert.equal(
window.groupOrderShop.cart[productId].name,
"Test Product",
"product name is correct"
);
assert.equal(
window.groupOrderShop.cart[productId].quantity,
2,
"product quantity is correct"
);
});
QUnit.test("can remove item from cart", function (assert) {
assert.expect(2);
// Add then remove
var productId = "123";
window.groupOrderShop.cart[productId] = {
name: "Test Product",
price: 10.5,
quantity: 2,
};
assert.equal(
Object.keys(window.groupOrderShop.cart).length,
1,
"cart has 1 item after add"
);
delete window.groupOrderShop.cart[productId];
assert.equal(
Object.keys(window.groupOrderShop.cart).length,
0,
"cart is empty after remove"
);
});
QUnit.test("can update item quantity", function (assert) {
assert.expect(3);
var productId = "123";
window.groupOrderShop.cart[productId] = {
name: "Test Product",
price: 10.5,
quantity: 2,
};
assert.equal(
window.groupOrderShop.cart[productId].quantity,
2,
"initial quantity is 2"
);
// Update quantity
window.groupOrderShop.cart[productId].quantity = 5;
assert.equal(
window.groupOrderShop.cart[productId].quantity,
5,
"quantity updated to 5"
);
assert.equal(
Object.keys(window.groupOrderShop.cart).length,
1,
"still only 1 item in cart"
);
});
QUnit.test("cart total calculates correctly", function (assert) {
assert.expect(1);
// Add multiple products
window.groupOrderShop.cart["123"] = {
name: "Product 1",
price: 10.0,
quantity: 2,
};
window.groupOrderShop.cart["456"] = {
name: "Product 2",
price: 5.5,
quantity: 3,
};
// Calculate total manually
var total = 0;
Object.keys(window.groupOrderShop.cart).forEach(function (productId) {
var item = window.groupOrderShop.cart[productId];
total += item.price * item.quantity;
});
// Expected: (10.00 * 2) + (5.50 * 3) = 20.00 + 16.50 = 36.50
assert.equal(total.toFixed(2), "36.50", "cart total is correct");
});
QUnit.test("localStorage saves cart correctly", function (assert) {
assert.expect(2);
var cartKey = "eskaera_1_cart";
var testCart = {
123: {
name: "Test Product",
price: 10.5,
quantity: 2,
},
};
// Save to localStorage
localStorage.setItem(cartKey, JSON.stringify(testCart));
// Retrieve and verify
var savedCart = JSON.parse(localStorage.getItem(cartKey));
assert.ok(savedCart, "cart was saved to localStorage");
assert.equal(savedCart["123"].name, "Test Product", "cart data is correct");
});
QUnit.test("labels object is initialized", function (assert) {
assert.expect(5);
assert.ok(window.groupOrderShop.labels, "labels object exists");
assert.equal(
window.groupOrderShop.labels["save_cart"],
"Save Cart",
"save_cart label exists"
);
assert.equal(
window.groupOrderShop.labels["reload_cart"],
"Reload Cart",
"reload_cart label exists"
);
assert.equal(
window.groupOrderShop.labels["checkout"],
"Checkout",
"checkout label exists"
);
assert.equal(
window.groupOrderShop.labels["confirm_order"],
"Confirm Order",
"confirm_order label exists"
);
});
QUnit.test("cart handles decimal quantities correctly", function (assert) {
assert.expect(2);
window.groupOrderShop.cart["123"] = {
name: "Weight Product",
price: 8.99,
quantity: 1.5,
};
var item = window.groupOrderShop.cart["123"];
var subtotal = item.price * item.quantity;
assert.equal(item.quantity, 1.5, "decimal quantity stored correctly");
assert.equal(
subtotal.toFixed(2),
"13.49",
"subtotal with decimal quantity is correct"
);
});
QUnit.test("cart handles zero quantity", function (assert) {
assert.expect(1);
window.groupOrderShop.cart["123"] = {
name: "Test Product",
price: 10.0,
quantity: 0,
};
var item = window.groupOrderShop.cart["123"];
var subtotal = item.price * item.quantity;
assert.equal(subtotal, 0, "zero quantity results in zero subtotal");
});
QUnit.test("cart handles multiple items with same price", function (assert) {
assert.expect(2);
window.groupOrderShop.cart["123"] = {
name: "Product A",
price: 10.0,
quantity: 2,
};
window.groupOrderShop.cart["456"] = {
name: "Product B",
price: 10.0,
quantity: 3,
};
var total = 0;
Object.keys(window.groupOrderShop.cart).forEach(function (productId) {
var item = window.groupOrderShop.cart[productId];
total += item.price * item.quantity;
});
assert.equal(Object.keys(window.groupOrderShop.cart).length, 2, "cart has 2 items");
assert.equal(total.toFixed(2), "50.00", "total is correct with same prices");
});
}
}, function() {
QUnit.test('groupOrderShop object initializes correctly', function(assert) {
assert.expect(3);
assert.ok(window.groupOrderShop, 'groupOrderShop object exists');
assert.equal(window.groupOrderShop.orderId, '1', 'orderId is set');
assert.ok(typeof window.groupOrderShop.cart === 'object', 'cart is an object');
});
QUnit.test('cart starts empty', function(assert) {
assert.expect(1);
var cartKeys = Object.keys(window.groupOrderShop.cart);
assert.equal(cartKeys.length, 0, 'cart has no items initially');
});
QUnit.test('can add item to cart', function(assert) {
assert.expect(4);
// Add a product to cart
var productId = '123';
var productData = {
name: 'Test Product',
price: 10.50,
quantity: 2
};
window.groupOrderShop.cart[productId] = productData;
assert.equal(Object.keys(window.groupOrderShop.cart).length, 1, 'cart has 1 item');
assert.ok(window.groupOrderShop.cart[productId], 'product exists in cart');
assert.equal(window.groupOrderShop.cart[productId].name, 'Test Product', 'product name is correct');
assert.equal(window.groupOrderShop.cart[productId].quantity, 2, 'product quantity is correct');
});
QUnit.test('can remove item from cart', function(assert) {
assert.expect(2);
// Add then remove
var productId = '123';
window.groupOrderShop.cart[productId] = {
name: 'Test Product',
price: 10.50,
quantity: 2
};
assert.equal(Object.keys(window.groupOrderShop.cart).length, 1, 'cart has 1 item after add');
delete window.groupOrderShop.cart[productId];
assert.equal(Object.keys(window.groupOrderShop.cart).length, 0, 'cart is empty after remove');
});
QUnit.test('can update item quantity', function(assert) {
assert.expect(3);
var productId = '123';
window.groupOrderShop.cart[productId] = {
name: 'Test Product',
price: 10.50,
quantity: 2
};
assert.equal(window.groupOrderShop.cart[productId].quantity, 2, 'initial quantity is 2');
// Update quantity
window.groupOrderShop.cart[productId].quantity = 5;
assert.equal(window.groupOrderShop.cart[productId].quantity, 5, 'quantity updated to 5');
assert.equal(Object.keys(window.groupOrderShop.cart).length, 1, 'still only 1 item in cart');
});
QUnit.test('cart total calculates correctly', function(assert) {
assert.expect(1);
// Add multiple products
window.groupOrderShop.cart['123'] = {
name: 'Product 1',
price: 10.00,
quantity: 2
};
window.groupOrderShop.cart['456'] = {
name: 'Product 2',
price: 5.50,
quantity: 3
};
// Calculate total manually
var total = 0;
Object.keys(window.groupOrderShop.cart).forEach(function(productId) {
var item = window.groupOrderShop.cart[productId];
total += item.price * item.quantity;
});
// Expected: (10.00 * 2) + (5.50 * 3) = 20.00 + 16.50 = 36.50
assert.equal(total.toFixed(2), '36.50', 'cart total is correct');
});
QUnit.test('localStorage saves cart correctly', function(assert) {
assert.expect(2);
var cartKey = 'eskaera_1_cart';
var testCart = {
'123': {
name: 'Test Product',
price: 10.50,
quantity: 2
}
};
// Save to localStorage
localStorage.setItem(cartKey, JSON.stringify(testCart));
// Retrieve and verify
var savedCart = JSON.parse(localStorage.getItem(cartKey));
assert.ok(savedCart, 'cart was saved to localStorage');
assert.equal(savedCart['123'].name, 'Test Product', 'cart data is correct');
});
QUnit.test('labels object is initialized', function(assert) {
assert.expect(5);
assert.ok(window.groupOrderShop.labels, 'labels object exists');
assert.equal(window.groupOrderShop.labels['save_cart'], 'Save Cart', 'save_cart label exists');
assert.equal(window.groupOrderShop.labels['reload_cart'], 'Reload Cart', 'reload_cart label exists');
assert.equal(window.groupOrderShop.labels['checkout'], 'Checkout', 'checkout label exists');
assert.equal(window.groupOrderShop.labels['confirm_order'], 'Confirm Order', 'confirm_order label exists');
});
QUnit.test('cart handles decimal quantities correctly', function(assert) {
assert.expect(2);
window.groupOrderShop.cart['123'] = {
name: 'Weight Product',
price: 8.99,
quantity: 1.5
};
var item = window.groupOrderShop.cart['123'];
var subtotal = item.price * item.quantity;
assert.equal(item.quantity, 1.5, 'decimal quantity stored correctly');
assert.equal(subtotal.toFixed(2), '13.49', 'subtotal with decimal quantity is correct');
});
QUnit.test('cart handles zero quantity', function(assert) {
assert.expect(1);
window.groupOrderShop.cart['123'] = {
name: 'Test Product',
price: 10.00,
quantity: 0
};
var item = window.groupOrderShop.cart['123'];
var subtotal = item.price * item.quantity;
assert.equal(subtotal, 0, 'zero quantity results in zero subtotal');
});
QUnit.test('cart handles multiple items with same price', function(assert) {
assert.expect(2);
window.groupOrderShop.cart['123'] = {
name: 'Product A',
price: 10.00,
quantity: 2
};
window.groupOrderShop.cart['456'] = {
name: 'Product B',
price: 10.00,
quantity: 3
};
var total = 0;
Object.keys(window.groupOrderShop.cart).forEach(function(productId) {
var item = window.groupOrderShop.cart[productId];
total += item.price * item.quantity;
});
assert.equal(Object.keys(window.groupOrderShop.cart).length, 2, 'cart has 2 items');
assert.equal(total.toFixed(2), '50.00', 'total is correct with same prices');
});
});
);
return {};
});

View file

@ -3,239 +3,247 @@
* Tests product filtering and search behavior
*/
odoo.define('website_sale_aplicoop.test_realtime_search', function (require) {
'use strict';
odoo.define("website_sale_aplicoop.test_realtime_search", function (require) {
"use strict";
var QUnit = window.QUnit;
QUnit.module('website_sale_aplicoop.realtime_search', {
beforeEach: function() {
// Setup: Create test DOM with product cards
this.$fixture = $('#qunit-fixture');
this.$fixture.append(
'<input type="text" id="realtime-search-input" />' +
'<select id="realtime-category-select">' +
'<option value="">All Categories</option>' +
'<option value="1">Category 1</option>' +
'<option value="2">Category 2</option>' +
'</select>' +
'<div class="product-card" data-product-name="Cabbage" data-category-id="1"></div>' +
'<div class="product-card" data-product-name="Carrot" data-category-id="1"></div>' +
'<div class="product-card" data-product-name="Apple" data-category-id="2"></div>' +
'<div class="product-card" data-product-name="Banana" data-category-id="2"></div>'
);
// Initialize search object
window.realtimeSearch = {
searchInput: document.getElementById('realtime-search-input'),
categorySelect: document.getElementById('realtime-category-select'),
productCards: document.querySelectorAll('.product-card'),
filterProducts: function() {
var searchTerm = this.searchInput.value.toLowerCase().trim();
var selectedCategory = this.categorySelect.value;
var visibleCount = 0;
var hiddenCount = 0;
this.productCards.forEach(function(card) {
var productName = card.getAttribute('data-product-name').toLowerCase();
var categoryId = card.getAttribute('data-category-id');
var matchesSearch = !searchTerm || productName.includes(searchTerm);
var matchesCategory = !selectedCategory || categoryId === selectedCategory;
if (matchesSearch && matchesCategory) {
card.classList.remove('d-none');
visibleCount++;
} else {
card.classList.add('d-none');
hiddenCount++;
}
});
return { visible: visibleCount, hidden: hiddenCount };
}
};
QUnit.module(
"website_sale_aplicoop.realtime_search",
{
beforeEach: function () {
// Setup: Create test DOM with product cards
this.$fixture = $("#qunit-fixture");
this.$fixture.append(
'<input type="text" id="realtime-search-input" />' +
'<select id="realtime-category-select">' +
'<option value="">All Categories</option>' +
'<option value="1">Category 1</option>' +
'<option value="2">Category 2</option>' +
"</select>" +
'<div class="product-card" data-product-name="Cabbage" data-category-id="1"></div>' +
'<div class="product-card" data-product-name="Carrot" data-category-id="1"></div>' +
'<div class="product-card" data-product-name="Apple" data-category-id="2"></div>' +
'<div class="product-card" data-product-name="Banana" data-category-id="2"></div>'
);
// Initialize search object
window.realtimeSearch = {
searchInput: document.getElementById("realtime-search-input"),
categorySelect: document.getElementById("realtime-category-select"),
productCards: document.querySelectorAll(".product-card"),
filterProducts: function () {
var searchTerm = this.searchInput.value.toLowerCase().trim();
var selectedCategory = this.categorySelect.value;
var visibleCount = 0;
var hiddenCount = 0;
this.productCards.forEach(function (card) {
var productName = card.getAttribute("data-product-name").toLowerCase();
var categoryId = card.getAttribute("data-category-id");
var matchesSearch = !searchTerm || productName.includes(searchTerm);
var matchesCategory =
!selectedCategory || categoryId === selectedCategory;
if (matchesSearch && matchesCategory) {
card.classList.remove("d-none");
visibleCount++;
} else {
card.classList.add("d-none");
hiddenCount++;
}
});
return { visible: visibleCount, hidden: hiddenCount };
},
};
},
afterEach: function () {
// Cleanup
this.$fixture.empty();
delete window.realtimeSearch;
},
},
afterEach: function() {
// Cleanup
this.$fixture.empty();
delete window.realtimeSearch;
function () {
QUnit.test("search input element exists", function (assert) {
assert.expect(1);
var searchInput = document.getElementById("realtime-search-input");
assert.ok(searchInput, "search input element exists");
});
QUnit.test("category select element exists", function (assert) {
assert.expect(1);
var categorySelect = document.getElementById("realtime-category-select");
assert.ok(categorySelect, "category select element exists");
});
QUnit.test("product cards are found", function (assert) {
assert.expect(1);
var productCards = document.querySelectorAll(".product-card");
assert.equal(productCards.length, 4, "found 4 product cards");
});
QUnit.test("search filters by product name", function (assert) {
assert.expect(2);
// Search for "cab"
window.realtimeSearch.searchInput.value = "cab";
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, "1 product visible (Cabbage)");
assert.equal(result.hidden, 3, "3 products hidden");
});
QUnit.test("search is case insensitive", function (assert) {
assert.expect(2);
// Search for "CARROT" in uppercase
window.realtimeSearch.searchInput.value = "CARROT";
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, "1 product visible (Carrot)");
assert.equal(result.hidden, 3, "3 products hidden");
});
QUnit.test("empty search shows all products", function (assert) {
assert.expect(2);
window.realtimeSearch.searchInput.value = "";
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 4, "all 4 products visible");
assert.equal(result.hidden, 0, "no products hidden");
});
QUnit.test("category filter works", function (assert) {
assert.expect(2);
// Select category 1
window.realtimeSearch.categorySelect.value = "1";
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 2, "2 products visible (Cabbage, Carrot)");
assert.equal(result.hidden, 2, "2 products hidden (Apple, Banana)");
});
QUnit.test("search and category filter work together", function (assert) {
assert.expect(2);
// Search for "ca" in category 1
window.realtimeSearch.searchInput.value = "ca";
window.realtimeSearch.categorySelect.value = "1";
var result = window.realtimeSearch.filterProducts();
// Should show: Cabbage, Carrot (both in category 1 and match "ca")
assert.equal(result.visible, 2, "2 products visible");
assert.equal(result.hidden, 2, "2 products hidden");
});
QUnit.test("search for non-existent product shows none", function (assert) {
assert.expect(2);
window.realtimeSearch.searchInput.value = "xyz123";
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 0, "no products visible");
assert.equal(result.hidden, 4, "all 4 products hidden");
});
QUnit.test("partial match works", function (assert) {
assert.expect(2);
// Search for "an" should match "Banana"
window.realtimeSearch.searchInput.value = "an";
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, "1 product visible (Banana)");
assert.equal(result.hidden, 3, "3 products hidden");
});
QUnit.test("search trims whitespace", function (assert) {
assert.expect(2);
// Search with extra whitespace
window.realtimeSearch.searchInput.value = " apple ";
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, "1 product visible (Apple)");
assert.equal(result.hidden, 3, "3 products hidden");
});
QUnit.test("d-none class is added to hidden products", function (assert) {
assert.expect(1);
window.realtimeSearch.searchInput.value = "cabbage";
window.realtimeSearch.filterProducts();
var productCards = document.querySelectorAll(".product-card");
var hiddenCards = Array.from(productCards).filter(function (card) {
return card.classList.contains("d-none");
});
assert.equal(hiddenCards.length, 3, "3 cards have d-none class");
});
QUnit.test("d-none class is removed from visible products", function (assert) {
assert.expect(2);
// First hide all
window.realtimeSearch.searchInput.value = "xyz";
window.realtimeSearch.filterProducts();
var allHidden = Array.from(window.realtimeSearch.productCards).every(function (
card
) {
return card.classList.contains("d-none");
});
assert.ok(allHidden, "all cards hidden initially");
// Then show all
window.realtimeSearch.searchInput.value = "";
window.realtimeSearch.filterProducts();
var allVisible = Array.from(window.realtimeSearch.productCards).every(function (
card
) {
return !card.classList.contains("d-none");
});
assert.ok(allVisible, "all cards visible after clearing search");
});
QUnit.test("filterProducts returns correct counts", function (assert) {
assert.expect(4);
// All visible
window.realtimeSearch.searchInput.value = "";
var result1 = window.realtimeSearch.filterProducts();
assert.equal(result1.visible + result1.hidden, 4, "total count is 4");
// 1 visible
window.realtimeSearch.searchInput.value = "apple";
var result2 = window.realtimeSearch.filterProducts();
assert.equal(result2.visible, 1, "visible count is 1");
// None visible
window.realtimeSearch.searchInput.value = "xyz";
var result3 = window.realtimeSearch.filterProducts();
assert.equal(result3.visible, 0, "visible count is 0");
// Category filter
window.realtimeSearch.searchInput.value = "";
window.realtimeSearch.categorySelect.value = "2";
var result4 = window.realtimeSearch.filterProducts();
assert.equal(result4.visible, 2, "category filter shows 2 products");
});
}
}, function() {
QUnit.test('search input element exists', function(assert) {
assert.expect(1);
var searchInput = document.getElementById('realtime-search-input');
assert.ok(searchInput, 'search input element exists');
});
QUnit.test('category select element exists', function(assert) {
assert.expect(1);
var categorySelect = document.getElementById('realtime-category-select');
assert.ok(categorySelect, 'category select element exists');
});
QUnit.test('product cards are found', function(assert) {
assert.expect(1);
var productCards = document.querySelectorAll('.product-card');
assert.equal(productCards.length, 4, 'found 4 product cards');
});
QUnit.test('search filters by product name', function(assert) {
assert.expect(2);
// Search for "cab"
window.realtimeSearch.searchInput.value = 'cab';
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, '1 product visible (Cabbage)');
assert.equal(result.hidden, 3, '3 products hidden');
});
QUnit.test('search is case insensitive', function(assert) {
assert.expect(2);
// Search for "CARROT" in uppercase
window.realtimeSearch.searchInput.value = 'CARROT';
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, '1 product visible (Carrot)');
assert.equal(result.hidden, 3, '3 products hidden');
});
QUnit.test('empty search shows all products', function(assert) {
assert.expect(2);
window.realtimeSearch.searchInput.value = '';
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 4, 'all 4 products visible');
assert.equal(result.hidden, 0, 'no products hidden');
});
QUnit.test('category filter works', function(assert) {
assert.expect(2);
// Select category 1
window.realtimeSearch.categorySelect.value = '1';
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 2, '2 products visible (Cabbage, Carrot)');
assert.equal(result.hidden, 2, '2 products hidden (Apple, Banana)');
});
QUnit.test('search and category filter work together', function(assert) {
assert.expect(2);
// Search for "ca" in category 1
window.realtimeSearch.searchInput.value = 'ca';
window.realtimeSearch.categorySelect.value = '1';
var result = window.realtimeSearch.filterProducts();
// Should show: Cabbage, Carrot (both in category 1 and match "ca")
assert.equal(result.visible, 2, '2 products visible');
assert.equal(result.hidden, 2, '2 products hidden');
});
QUnit.test('search for non-existent product shows none', function(assert) {
assert.expect(2);
window.realtimeSearch.searchInput.value = 'xyz123';
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 0, 'no products visible');
assert.equal(result.hidden, 4, 'all 4 products hidden');
});
QUnit.test('partial match works', function(assert) {
assert.expect(2);
// Search for "an" should match "Banana"
window.realtimeSearch.searchInput.value = 'an';
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, '1 product visible (Banana)');
assert.equal(result.hidden, 3, '3 products hidden');
});
QUnit.test('search trims whitespace', function(assert) {
assert.expect(2);
// Search with extra whitespace
window.realtimeSearch.searchInput.value = ' apple ';
var result = window.realtimeSearch.filterProducts();
assert.equal(result.visible, 1, '1 product visible (Apple)');
assert.equal(result.hidden, 3, '3 products hidden');
});
QUnit.test('d-none class is added to hidden products', function(assert) {
assert.expect(1);
window.realtimeSearch.searchInput.value = 'cabbage';
window.realtimeSearch.filterProducts();
var productCards = document.querySelectorAll('.product-card');
var hiddenCards = Array.from(productCards).filter(function(card) {
return card.classList.contains('d-none');
});
assert.equal(hiddenCards.length, 3, '3 cards have d-none class');
});
QUnit.test('d-none class is removed from visible products', function(assert) {
assert.expect(2);
// First hide all
window.realtimeSearch.searchInput.value = 'xyz';
window.realtimeSearch.filterProducts();
var allHidden = Array.from(window.realtimeSearch.productCards).every(function(card) {
return card.classList.contains('d-none');
});
assert.ok(allHidden, 'all cards hidden initially');
// Then show all
window.realtimeSearch.searchInput.value = '';
window.realtimeSearch.filterProducts();
var allVisible = Array.from(window.realtimeSearch.productCards).every(function(card) {
return !card.classList.contains('d-none');
});
assert.ok(allVisible, 'all cards visible after clearing search');
});
QUnit.test('filterProducts returns correct counts', function(assert) {
assert.expect(4);
// All visible
window.realtimeSearch.searchInput.value = '';
var result1 = window.realtimeSearch.filterProducts();
assert.equal(result1.visible + result1.hidden, 4, 'total count is 4');
// 1 visible
window.realtimeSearch.searchInput.value = 'apple';
var result2 = window.realtimeSearch.filterProducts();
assert.equal(result2.visible, 1, 'visible count is 1');
// None visible
window.realtimeSearch.searchInput.value = 'xyz';
var result3 = window.realtimeSearch.filterProducts();
assert.equal(result3.visible, 0, 'visible count is 0');
// Category filter
window.realtimeSearch.searchInput.value = '';
window.realtimeSearch.categorySelect.value = '2';
var result4 = window.realtimeSearch.filterProducts();
assert.equal(result4.visible, 2, 'category filter shows 2 products');
});
});
);
return {};
});

View file

@ -1,10 +1,10 @@
odoo.define('website_sale_aplicoop.test_suite', function (require) {
'use strict';
odoo.define("website_sale_aplicoop.test_suite", function (require) {
"use strict";
// Import all test modules
require('website_sale_aplicoop.test_cart_functions');
require('website_sale_aplicoop.test_tooltips_labels');
require('website_sale_aplicoop.test_realtime_search');
require("website_sale_aplicoop.test_cart_functions");
require("website_sale_aplicoop.test_tooltips_labels");
require("website_sale_aplicoop.test_realtime_search");
// Test suite is automatically registered by importing modules
});

View file

@ -3,185 +3,214 @@
* Tests tooltip initialization and label loading
*/
odoo.define('website_sale_aplicoop.test_tooltips_labels', function (require) {
'use strict';
odoo.define("website_sale_aplicoop.test_tooltips_labels", function (require) {
"use strict";
var QUnit = window.QUnit;
QUnit.module('website_sale_aplicoop.tooltips_labels', {
beforeEach: function() {
// Setup: Create test DOM elements
this.$fixture = $('#qunit-fixture');
// Add test buttons with tooltip labels
this.$fixture.append(
'<button id="test-btn-1" data-tooltip-label="save_cart">Save</button>' +
'<button id="test-btn-2" data-tooltip-label="checkout">Checkout</button>' +
'<button id="test-btn-3" data-tooltip-label="reload_cart">Reload</button>'
);
// Initialize groupOrderShop
window.groupOrderShop = {
orderId: '1',
cart: {},
labels: {
'save_cart': 'Guardar Carrito',
'reload_cart': 'Recargar Carrito',
'checkout': 'Proceder al Pago',
'confirm_order': 'Confirmar Pedido',
'back_to_cart': 'Volver al Carrito'
},
_initTooltips: function() {
var labels = window.groupOrderShop.labels || this.labels || {};
var tooltipElements = document.querySelectorAll('[data-tooltip-label]');
tooltipElements.forEach(function(el) {
var labelKey = el.getAttribute('data-tooltip-label');
if (labelKey && labels[labelKey]) {
el.setAttribute('title', labels[labelKey]);
}
});
}
};
QUnit.module(
"website_sale_aplicoop.tooltips_labels",
{
beforeEach: function () {
// Setup: Create test DOM elements
this.$fixture = $("#qunit-fixture");
// Add test buttons with tooltip labels
this.$fixture.append(
'<button id="test-btn-1" data-tooltip-label="save_cart">Save</button>' +
'<button id="test-btn-2" data-tooltip-label="checkout">Checkout</button>' +
'<button id="test-btn-3" data-tooltip-label="reload_cart">Reload</button>'
);
// Initialize groupOrderShop
window.groupOrderShop = {
orderId: "1",
cart: {},
labels: {
save_cart: "Guardar Carrito",
reload_cart: "Recargar Carrito",
checkout: "Proceder al Pago",
confirm_order: "Confirmar Pedido",
back_to_cart: "Volver al Carrito",
},
_initTooltips: function () {
var labels = window.groupOrderShop.labels || this.labels || {};
var tooltipElements = document.querySelectorAll("[data-tooltip-label]");
tooltipElements.forEach(function (el) {
var labelKey = el.getAttribute("data-tooltip-label");
if (labelKey && labels[labelKey]) {
el.setAttribute("title", labels[labelKey]);
}
});
},
};
},
afterEach: function () {
// Cleanup
this.$fixture.empty();
delete window.groupOrderShop;
},
},
afterEach: function() {
// Cleanup
this.$fixture.empty();
delete window.groupOrderShop;
}
}, function() {
function () {
QUnit.test("tooltips are initialized from labels", function (assert) {
assert.expect(3);
QUnit.test('tooltips are initialized from labels', function(assert) {
assert.expect(3);
// Initialize tooltips
window.groupOrderShop._initTooltips();
var btn1 = document.getElementById('test-btn-1');
var btn2 = document.getElementById('test-btn-2');
var btn3 = document.getElementById('test-btn-3');
assert.equal(btn1.getAttribute('title'), 'Guardar Carrito', 'save_cart tooltip is correct');
assert.equal(btn2.getAttribute('title'), 'Proceder al Pago', 'checkout tooltip is correct');
assert.equal(btn3.getAttribute('title'), 'Recargar Carrito', 'reload_cart tooltip is correct');
});
QUnit.test('tooltips handle missing labels gracefully', function(assert) {
assert.expect(1);
// Add button with non-existent label
this.$fixture.append('<button id="test-btn-4" data-tooltip-label="non_existent">Test</button>');
window.groupOrderShop._initTooltips();
var btn4 = document.getElementById('test-btn-4');
var title = btn4.getAttribute('title');
// Should be null or empty since label doesn't exist
assert.ok(!title || title === '', 'missing label does not set tooltip');
});
QUnit.test('labels object contains expected keys', function(assert) {
assert.expect(5);
var labels = window.groupOrderShop.labels;
assert.ok('save_cart' in labels, 'has save_cart label');
assert.ok('reload_cart' in labels, 'has reload_cart label');
assert.ok('checkout' in labels, 'has checkout label');
assert.ok('confirm_order' in labels, 'has confirm_order label');
assert.ok('back_to_cart' in labels, 'has back_to_cart label');
});
QUnit.test('labels are strings', function(assert) {
assert.expect(5);
var labels = window.groupOrderShop.labels;
assert.equal(typeof labels.save_cart, 'string', 'save_cart is string');
assert.equal(typeof labels.reload_cart, 'string', 'reload_cart is string');
assert.equal(typeof labels.checkout, 'string', 'checkout is string');
assert.equal(typeof labels.confirm_order, 'string', 'confirm_order is string');
assert.equal(typeof labels.back_to_cart, 'string', 'back_to_cart is string');
});
QUnit.test('_initTooltips uses window.groupOrderShop.labels', function(assert) {
assert.expect(1);
// Update global labels
window.groupOrderShop.labels = {
'save_cart': 'Updated Label',
'checkout': 'Updated Checkout',
'reload_cart': 'Updated Reload'
};
window.groupOrderShop._initTooltips();
var btn1 = document.getElementById('test-btn-1');
assert.equal(btn1.getAttribute('title'), 'Updated Label', 'uses updated global labels');
});
QUnit.test('tooltips can be reinitialized', function(assert) {
assert.expect(2);
// First initialization
window.groupOrderShop._initTooltips();
var btn1 = document.getElementById('test-btn-1');
assert.equal(btn1.getAttribute('title'), 'Guardar Carrito', 'first init correct');
// Update labels and reinitialize
window.groupOrderShop.labels.save_cart = 'New Translation';
window.groupOrderShop._initTooltips();
assert.equal(btn1.getAttribute('title'), 'New Translation', 'reinitialized with new label');
});
QUnit.test('elements without data-tooltip-label are ignored', function(assert) {
assert.expect(1);
this.$fixture.append('<button id="test-btn-no-label">No Label</button>');
window.groupOrderShop._initTooltips();
var btnNoLabel = document.getElementById('test-btn-no-label');
var title = btnNoLabel.getAttribute('title');
assert.ok(!title || title === '', 'button without data-tooltip-label has no title');
});
QUnit.test('querySelectorAll finds all tooltip elements', function(assert) {
assert.expect(1);
var tooltipElements = document.querySelectorAll('[data-tooltip-label]');
// We have 3 buttons with data-tooltip-label
assert.equal(tooltipElements.length, 3, 'finds all 3 elements with data-tooltip-label');
});
QUnit.test('labels survive JSON serialization', function(assert) {
assert.expect(2);
var labels = window.groupOrderShop.labels;
var serialized = JSON.stringify(labels);
var deserialized = JSON.parse(serialized);
assert.ok(serialized, 'labels can be serialized to JSON');
assert.deepEqual(deserialized, labels, 'deserialized labels match original');
});
QUnit.test('empty labels object does not break initialization', function(assert) {
assert.expect(1);
window.groupOrderShop.labels = {};
try {
// Initialize tooltips
window.groupOrderShop._initTooltips();
assert.ok(true, 'initialization with empty labels does not throw error');
} catch (e) {
assert.ok(false, 'initialization threw error: ' + e.message);
}
});
});
var btn1 = document.getElementById("test-btn-1");
var btn2 = document.getElementById("test-btn-2");
var btn3 = document.getElementById("test-btn-3");
assert.equal(
btn1.getAttribute("title"),
"Guardar Carrito",
"save_cart tooltip is correct"
);
assert.equal(
btn2.getAttribute("title"),
"Proceder al Pago",
"checkout tooltip is correct"
);
assert.equal(
btn3.getAttribute("title"),
"Recargar Carrito",
"reload_cart tooltip is correct"
);
});
QUnit.test("tooltips handle missing labels gracefully", function (assert) {
assert.expect(1);
// Add button with non-existent label
this.$fixture.append(
'<button id="test-btn-4" data-tooltip-label="non_existent">Test</button>'
);
window.groupOrderShop._initTooltips();
var btn4 = document.getElementById("test-btn-4");
var title = btn4.getAttribute("title");
// Should be null or empty since label doesn't exist
assert.ok(!title || title === "", "missing label does not set tooltip");
});
QUnit.test("labels object contains expected keys", function (assert) {
assert.expect(5);
var labels = window.groupOrderShop.labels;
assert.ok("save_cart" in labels, "has save_cart label");
assert.ok("reload_cart" in labels, "has reload_cart label");
assert.ok("checkout" in labels, "has checkout label");
assert.ok("confirm_order" in labels, "has confirm_order label");
assert.ok("back_to_cart" in labels, "has back_to_cart label");
});
QUnit.test("labels are strings", function (assert) {
assert.expect(5);
var labels = window.groupOrderShop.labels;
assert.equal(typeof labels.save_cart, "string", "save_cart is string");
assert.equal(typeof labels.reload_cart, "string", "reload_cart is string");
assert.equal(typeof labels.checkout, "string", "checkout is string");
assert.equal(typeof labels.confirm_order, "string", "confirm_order is string");
assert.equal(typeof labels.back_to_cart, "string", "back_to_cart is string");
});
QUnit.test("_initTooltips uses window.groupOrderShop.labels", function (assert) {
assert.expect(1);
// Update global labels
window.groupOrderShop.labels = {
save_cart: "Updated Label",
checkout: "Updated Checkout",
reload_cart: "Updated Reload",
};
window.groupOrderShop._initTooltips();
var btn1 = document.getElementById("test-btn-1");
assert.equal(
btn1.getAttribute("title"),
"Updated Label",
"uses updated global labels"
);
});
QUnit.test("tooltips can be reinitialized", function (assert) {
assert.expect(2);
// First initialization
window.groupOrderShop._initTooltips();
var btn1 = document.getElementById("test-btn-1");
assert.equal(btn1.getAttribute("title"), "Guardar Carrito", "first init correct");
// Update labels and reinitialize
window.groupOrderShop.labels.save_cart = "New Translation";
window.groupOrderShop._initTooltips();
assert.equal(
btn1.getAttribute("title"),
"New Translation",
"reinitialized with new label"
);
});
QUnit.test("elements without data-tooltip-label are ignored", function (assert) {
assert.expect(1);
this.$fixture.append('<button id="test-btn-no-label">No Label</button>');
window.groupOrderShop._initTooltips();
var btnNoLabel = document.getElementById("test-btn-no-label");
var title = btnNoLabel.getAttribute("title");
assert.ok(!title || title === "", "button without data-tooltip-label has no title");
});
QUnit.test("querySelectorAll finds all tooltip elements", function (assert) {
assert.expect(1);
var tooltipElements = document.querySelectorAll("[data-tooltip-label]");
// We have 3 buttons with data-tooltip-label
assert.equal(
tooltipElements.length,
3,
"finds all 3 elements with data-tooltip-label"
);
});
QUnit.test("labels survive JSON serialization", function (assert) {
assert.expect(2);
var labels = window.groupOrderShop.labels;
var serialized = JSON.stringify(labels);
var deserialized = JSON.parse(serialized);
assert.ok(serialized, "labels can be serialized to JSON");
assert.deepEqual(deserialized, labels, "deserialized labels match original");
});
QUnit.test("empty labels object does not break initialization", function (assert) {
assert.expect(1);
window.groupOrderShop.labels = {};
try {
window.groupOrderShop._initTooltips();
assert.ok(true, "initialization with empty labels does not throw error");
} catch (e) {
assert.ok(false, "initialization threw error: " + e.message);
}
});
}
);
return {};
});