Aplicoop desde el repo de kidekoop
This commit is contained in:
parent
69917d1ec2
commit
7cff89e418
93 changed files with 313992 additions and 0 deletions
262
website_sale_aplicoop/static/tests/README.md
Normal file
262
website_sale_aplicoop/static/tests/README.md
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
# JavaScript Tests for website_sale_aplicoop
|
||||
|
||||
This directory contains QUnit tests for the JavaScript functionality of the website_sale_aplicoop module.
|
||||
|
||||
## Test Files
|
||||
|
||||
### 1. test_cart_functions.js
|
||||
Tests for core cart functionality:
|
||||
- Cart initialization
|
||||
- Adding items to cart
|
||||
- Removing items from cart
|
||||
- Updating quantities
|
||||
- Calculating totals
|
||||
- localStorage persistence
|
||||
- Decimal quantity handling
|
||||
- Zero quantity handling
|
||||
|
||||
### 2. test_tooltips_labels.js
|
||||
Tests for tooltip and label functionality:
|
||||
- Tooltip initialization from labels
|
||||
- Label loading and structure
|
||||
- Missing label handling
|
||||
- Label reinitialization
|
||||
- JSON serialization of labels
|
||||
- Empty labels handling
|
||||
|
||||
### 3. test_realtime_search.js
|
||||
Tests for real-time product search:
|
||||
- Search input functionality
|
||||
- Category filtering
|
||||
- Combined search and category filters
|
||||
- Case-insensitive search
|
||||
- Partial matching
|
||||
- Whitespace trimming
|
||||
- Product visibility toggling
|
||||
- Result counting
|
||||
|
||||
### 4. test_suite.js
|
||||
Main test suite that imports all test modules.
|
||||
|
||||
## Running the Tests
|
||||
|
||||
### Method 1: Via Odoo Test Runner (Recommended)
|
||||
|
||||
1. **Access the test interface:**
|
||||
```
|
||||
http://localhost:8069/web/tests?mod=website_sale_aplicoop
|
||||
```
|
||||
|
||||
2. **Run specific test modules:**
|
||||
```
|
||||
http://localhost:8069/web/tests?mod=website_sale_aplicoop.test_cart_functions
|
||||
http://localhost:8069/web/tests?mod=website_sale_aplicoop.test_tooltips_labels
|
||||
http://localhost:8069/web/tests?mod=website_sale_aplicoop.test_realtime_search
|
||||
```
|
||||
|
||||
3. **View results:**
|
||||
- Tests run in the browser
|
||||
- Results displayed in QUnit interface
|
||||
- Green = Pass, Red = Fail
|
||||
- Click failed tests to see details
|
||||
|
||||
### Method 2: Via Command Line
|
||||
|
||||
Run Odoo with test mode:
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
docker-compose exec odoo odoo -d odoo --test-enable --stop-after-init
|
||||
|
||||
# Run with specific test tags
|
||||
docker-compose exec odoo odoo -d odoo --test-enable --test-tags=website_sale_aplicoop --stop-after-init
|
||||
|
||||
# Run in verbose mode for more details
|
||||
docker-compose exec odoo odoo -d odoo --test-enable --log-level=test --stop-after-init
|
||||
```
|
||||
|
||||
### Method 3: Via Browser Console
|
||||
|
||||
1. Open the application page in browser
|
||||
2. Open browser console (F12)
|
||||
3. Run:
|
||||
```javascript
|
||||
QUnit.start();
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Cart Functions (11 tests)
|
||||
- ✅ Object initialization
|
||||
- ✅ Empty cart verification
|
||||
- ✅ Add item to cart
|
||||
- ✅ Remove item from cart
|
||||
- ✅ Update quantity
|
||||
- ✅ Calculate total
|
||||
- ✅ localStorage persistence
|
||||
- ✅ Decimal quantities
|
||||
- ✅ Zero quantity handling
|
||||
- ✅ Same price products
|
||||
- ✅ Label initialization
|
||||
|
||||
### Tooltips & Labels (10 tests)
|
||||
- ✅ Tooltip initialization
|
||||
- ✅ Missing label handling
|
||||
- ✅ Label object structure
|
||||
- ✅ Label data types
|
||||
- ✅ Global label usage
|
||||
- ✅ Reinitialization
|
||||
- ✅ Elements without tooltips
|
||||
- ✅ querySelectorAll functionality
|
||||
- ✅ JSON serialization
|
||||
- ✅ Empty labels handling
|
||||
|
||||
### Realtime Search (13 tests)
|
||||
- ✅ Element existence
|
||||
- ✅ Search by name
|
||||
- ✅ Case insensitive search
|
||||
- ✅ Empty search shows all
|
||||
- ✅ Category filtering
|
||||
- ✅ Combined filters
|
||||
- ✅ Non-existent product
|
||||
- ✅ Partial matching
|
||||
- ✅ Whitespace trimming
|
||||
- ✅ CSS class toggling
|
||||
- ✅ Visibility restoration
|
||||
- ✅ Result counting
|
||||
|
||||
**Total: 34 tests**
|
||||
|
||||
## Adding New Tests
|
||||
|
||||
1. Create a new test file in `/static/tests/`:
|
||||
```javascript
|
||||
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
|
||||
},
|
||||
afterEach: function() {
|
||||
// Cleanup code
|
||||
}
|
||||
}, function() {
|
||||
QUnit.test('test description', function(assert) {
|
||||
assert.expect(1);
|
||||
assert.ok(true, 'test passes');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
2. Add to `test_suite.js`:
|
||||
```javascript
|
||||
require('website_sale_aplicoop.test_my_feature');
|
||||
```
|
||||
|
||||
3. Add to `__manifest__.py` assets:
|
||||
```python
|
||||
'web.assets_tests': [
|
||||
# ... existing files ...
|
||||
'website_sale_aplicoop/static/tests/test_my_feature.js',
|
||||
],
|
||||
```
|
||||
|
||||
4. Reload module and run tests
|
||||
|
||||
## QUnit Assertions Reference
|
||||
|
||||
Common assertions used in tests:
|
||||
|
||||
- `assert.ok(value, message)` - Verify truthy value
|
||||
- `assert.equal(actual, expected, message)` - Loose equality (==)
|
||||
- `assert.strictEqual(actual, expected, message)` - Strict equality (===)
|
||||
- `assert.deepEqual(actual, expected, message)` - Deep object comparison
|
||||
- `assert.notOk(value, message)` - Verify falsy value
|
||||
- `assert.notEqual(actual, expected, message)` - Verify not equal
|
||||
- `assert.expect(count)` - Set expected assertion count
|
||||
|
||||
## Debugging Tests
|
||||
|
||||
### View Test Output
|
||||
- Open browser console (F12)
|
||||
- Check "Console" tab for test logs
|
||||
- Check "Network" tab for failed requests
|
||||
|
||||
### Debug Individual Test
|
||||
```javascript
|
||||
QUnit.test('test name', function(assert) {
|
||||
debugger; // Browser will pause here
|
||||
// ... test code ...
|
||||
});
|
||||
```
|
||||
|
||||
### Run Single Test
|
||||
```javascript
|
||||
QUnit.only('test name', function(assert) {
|
||||
// Only this test will run
|
||||
});
|
||||
```
|
||||
|
||||
### Skip Test
|
||||
```javascript
|
||||
QUnit.skip('test name', function(assert) {
|
||||
// This test will be skipped
|
||||
});
|
||||
```
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
Tests can be integrated into CI/CD pipelines:
|
||||
|
||||
```bash
|
||||
# In CI script
|
||||
docker-compose up -d
|
||||
docker-compose exec -T odoo odoo -d odoo --test-enable --test-tags=website_sale_aplicoop --stop-after-init
|
||||
exit_code=$?
|
||||
docker-compose down
|
||||
exit $exit_code
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Tests not loading
|
||||
- Verify module is installed and updated
|
||||
- Check browser console for JavaScript errors
|
||||
- Verify assets are properly declared in __manifest__.py
|
||||
- Clear browser cache and restart Odoo
|
||||
|
||||
### Tests failing unexpectedly
|
||||
- Check if labels are loaded (`window.groupOrderShop.labels`)
|
||||
- Verify DOM elements exist before testing
|
||||
- Check for timing issues (use beforeEach/afterEach)
|
||||
- Verify localStorage is not blocked by browser
|
||||
|
||||
### Assets not found
|
||||
- Update module: `docker-compose exec odoo odoo -d odoo -u website_sale_aplicoop`
|
||||
- Clear assets cache: `docker-compose exec odoo rm -rf /var/lib/odoo/filestore/odoo/web/static/lib/minified_assets/`
|
||||
- Restart Odoo
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use beforeEach/afterEach**: Clean up DOM and global state
|
||||
2. **Expect assertions**: Always use `assert.expect(n)` to verify all assertions run
|
||||
3. **Test isolation**: Each test should be independent
|
||||
4. **Descriptive names**: Use clear, descriptive test names
|
||||
5. **One concept per test**: Test one thing at a time
|
||||
6. **Mock external dependencies**: Don't rely on real API calls
|
||||
7. **Test edge cases**: Empty strings, null values, extreme numbers
|
||||
|
||||
## Resources
|
||||
|
||||
- [QUnit Documentation](https://qunitjs.com/)
|
||||
- [Odoo JavaScript Testing](https://www.odoo.com/documentation/18.0/developer/reference/frontend/javascript_testing.html)
|
||||
- [MDN Web Docs - Testing](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing)
|
||||
|
||||
---
|
||||
|
||||
**Maintainer**: Criptomart
|
||||
**License**: AGPL-3.0
|
||||
**Last Updated**: February 3, 2026
|
||||
224
website_sale_aplicoop/static/tests/test_cart_functions.js
Normal file
224
website_sale_aplicoop/static/tests/test_cart_functions.js
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/**
|
||||
* QUnit Tests for Cart Functions
|
||||
* Tests core cart functionality (add, remove, update, calculate)
|
||||
*/
|
||||
|
||||
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();
|
||||
},
|
||||
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.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 {};
|
||||
});
|
||||
241
website_sale_aplicoop/static/tests/test_realtime_search.js
Normal file
241
website_sale_aplicoop/static/tests/test_realtime_search.js
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/**
|
||||
* QUnit Tests for Realtime Search Functionality
|
||||
* Tests product filtering and search behavior
|
||||
*/
|
||||
|
||||
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 };
|
||||
}
|
||||
};
|
||||
},
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
return {};
|
||||
});
|
||||
10
website_sale_aplicoop/static/tests/test_suite.js
Normal file
10
website_sale_aplicoop/static/tests/test_suite.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
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');
|
||||
|
||||
// Test suite is automatically registered by importing modules
|
||||
});
|
||||
187
website_sale_aplicoop/static/tests/test_tooltips_labels.js
Normal file
187
website_sale_aplicoop/static/tests/test_tooltips_labels.js
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/**
|
||||
* QUnit Tests for Tooltip and Label Functions
|
||||
* Tests tooltip initialization and label loading
|
||||
*/
|
||||
|
||||
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]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
afterEach: function() {
|
||||
// Cleanup
|
||||
this.$fixture.empty();
|
||||
delete window.groupOrderShop;
|
||||
}
|
||||
}, function() {
|
||||
|
||||
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 {
|
||||
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 {};
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue