/** @odoo-module */ import { click, getFixture, nextTick, patchWithCleanup } from '@web/../tests/helpers/utils'; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; import { LunchKanbanRenderer } from '@lunch/views/kanban'; let target; let serverData; let lunchInfos; async function makeLunchView(extraArgs = {}) { return await makeView( Object.assign({ serverData, type: "kanban", resModel: "lunch.product", arch: `
`, mockRPC: (route, args) => { if (route == '/lunch/user_location_get') { return Promise.resolve(serverData.models['lunch.location'].records[0].id); } else if (route == '/lunch/infos') { return Promise.resolve(lunchInfos); } } }, extraArgs )); } QUnit.module('Lunch', {}, function() { QUnit.module('LunchKanban', (hooks) => { hooks.beforeEach(() => { target = getFixture(); serverData = { models: { 'lunch.product': { fields: { id: { string: "ID", type: "integer" }, name: { string: 'Name', type: 'char' }, is_available_at: { string: 'Available', type: 'integer' }, price: { string: 'Price', type: 'float', }, }, records: [ { id: 1, name: "Big Plate", is_available_at: 1, price: 4.95, }, { id: 2, name: "Small Plate", is_available_at: 2, price: 6.99, }, { id: 3, name: "Just One Plate", is_available_at: 2, price: 5.87, }, ] }, 'lunch.location': { fields: { name: { string: 'Name', type: 'char' }, }, records: [ { id: 1, name: "Old Office" }, { id: 2, name: "New Office" }, ] }, 'lunch.order': { fields: { product_id: { string: 'Product', type: 'many2one', relation: 'lunch.product', }, } }, 'res.users': { fields: { share: { type: 'boolean', }, }, records: [ { id: 1, name: 'Johnny Hache', share: false, }, { id: 2, name: 'David Elora', share: false, } ] } }, views: { 'lunch.order,false,form': `
` } }; lunchInfos = { username: "Johnny Hache", wallet: 12.05, is_manager: false, currency: { symbol: "€", position: "after", }, user_location: [1, "Old Office"], alerts: [], lines: [], }; setupViewRegistries(); }); QUnit.test("Basic rendering", async function (assert) { assert.expect(4); await makeLunchView(); assert.containsOnce(target, '.o_lunch_banner'); assert.containsNone(target, '.o_lunch_content .alert'); assert.containsOnce(target, '.o_kanban_record:not(.o_kanban_ghost)', 1); const lunchDashboard = target.querySelector('.o_lunch_banner'); const lunchUser = lunchDashboard.querySelector('.lunch_user span'); assert.equal(lunchUser.innerText, 'Johnny Hache'); }); QUnit.test("Open product", async function (assert) { assert.expect(2); await makeLunchView(); patchWithCleanup(LunchKanbanRenderer.prototype, { openOrderLine(productId, orderId) { assert.equal(productId, 1); } }); assert.containsOnce(target, '.o_kanban_record:not(.o_kanban_ghost)'); click(target, '.o_kanban_record:not(.o_kanban_ghost)'); }); QUnit.test("Basic rendering with alerts", async function (assert) { assert.expect(2); let userInfos = { ...lunchInfos, alerts: [ { id: 1, message: 'free boudin compote for everyone', } ] }; await makeLunchView({ mockRPC: (route, args) => { if (route == '/lunch/user_location_get') { return Promise.resolve(userInfos.user_location[0]); } else if (route == '/lunch/infos') { return Promise.resolve(userInfos); } } }); assert.containsOnce(target, '.o_lunch_content .alert'); assert.equal(target.querySelector('.o_lunch_content .alert').innerText, 'free boudin compote for everyone'); }); QUnit.test("Open product", async function (assert) { assert.expect(2); await makeLunchView(); patchWithCleanup(LunchKanbanRenderer.prototype, { openOrderLine(productId, orderId) { assert.equal(productId, 1); } }); assert.containsOnce(target, '.o_kanban_record:not(.o_kanban_ghost)'); click(target, '.o_kanban_record:not(.o_kanban_ghost)'); }); QUnit.test("Location change", async function (assert) { assert.expect(3); let userInfos = { ...lunchInfos }; await makeLunchView({ mockRPC: (route, args) => { if (route == '/lunch/user_location_get') { return Promise.resolve(userInfos.user_location[0]); } else if (route == '/lunch/infos') { return Promise.resolve(userInfos); } else if (route == '/lunch/user_location_set') { assert.equal(args.location_id, 2); userInfos.user_location = [2, "New Office"]; return Promise.resolve(true); } } }); click(target, '.lunch_location input'); await nextTick(); assert.containsOnce(target, '.lunch_location .dropdown-item:contains(New Office)'); click(target, '.lunch_location li:not(.o_m2o_dropdown_option) .dropdown-item:not(.ui-state-active)'); await nextTick(); assert.containsN(target, 'div[role=article].o_kanban_record', 2); }); QUnit.test("Manager: user change", async function (assert) { assert.expect(8); let userInfos = { ...lunchInfos, is_manager: true }; let expectedUserId = false; // false as we are requesting for the current user await makeLunchView({ mockRPC: (route, args) => { if (route == '/lunch/user_location_get') { return Promise.resolve(userInfos.user_location[0]); } else if (route == '/lunch/infos') { assert.equal(expectedUserId, args.user_id); if (expectedUserId === 2) { userInfos = { ...userInfos, username: 'David Elora', wallet: -10000, }; } return Promise.resolve(userInfos); } else if (route == '/lunch/user_location_set') { assert.equal(args.location_id, 2); userInfos.user_location = [2, "New Office"]; return Promise.resolve(true); } } }); assert.containsOnce(target, '.lunch_user input'); click(target, '.lunch_user input'); await nextTick(); assert.containsOnce(target, '.lunch_user .dropdown-item:contains(David Elora)'); expectedUserId = 2; click(target, '.lunch_user li:not(.o_m2o_dropdown_option) .dropdown-item:not(.ui-state-active)'); await nextTick(); const wallet = target.querySelector('.o_lunch_banner .col-9 > .d-flex > span:nth-child(2)'); assert.equal(wallet.innerText, '-10000.00€', 'David Elora is poor') click(target, '.lunch_location input'); await nextTick(); click(target, '.lunch_location li:not(.o_m2o_dropdown_option) .dropdown-item:not(.ui-state-active)'); await nextTick(); const user = target.querySelector('.lunch_user input'); assert.equal(user.value, 'David Elora', 'changing location should not reset user'); }); QUnit.test("Trash existing order", async function (assert) { assert.expect(5); let userInfos = { ...lunchInfos, lines: [ { id: 1, product: [1, "Big Plate", "4.95"], toppings: [], quantity: 1, price: 4.95, raw_state: "new", state: "To Order", note: false } ], raw_state: "new", total: "4.95", paid_subtotal: "0", unpaid_subtotal: "4.95", }; await makeLunchView({ mockRPC: (route, args) => { if (route == '/lunch/user_location_get') { return Promise.resolve(userInfos.user_location[0]); } else if (route == '/lunch/infos') { return Promise.resolve(userInfos); } else if (route == '/lunch/trash') { userInfos = { ...userInfos, lines: [], raw_state: false, total: 0, }; return Promise.resolve(true); } } }); assert.containsN(target, 'div.o_lunch_banner > .row > div', 3); assert.containsOnce(target, 'div.o_lunch_banner > .row > div:nth-child(2) button.fa-trash', 'should have trash icon'); assert.containsOnce(target, 'div.o_lunch_banner > .row > div:nth-child(2) ul > li', 'should have one order line'); assert.containsOnce(target, 'div.o_lunch_banner > .row > div:nth-child(3) button:contains(Order Now)'); click(target, 'div.o_lunch_banner > .row > div:nth-child(2) button.fa-trash'); await nextTick(); assert.containsN(target, 'div.o_lunch_banner > .row > div', 1); }); QUnit.test("Change existing order", async function (assert) { assert.expect(1); let userInfos = { ...lunchInfos, lines: [ { id: 1, product: [1, "Big Plate", "4.95"], toppings: [], quantity: 1, price: 4.95, raw_state: "new", state: "To Order", note: false } ], raw_state: "new", total: "4.95", paid_subtotal: "0", unpaid_subtotal: "4.95", }; await makeLunchView({ mockRPC: (route, args) => { if (route == '/lunch/user_location_get') { return Promise.resolve(userInfos.user_location[0]); } else if (route == '/lunch/infos') { return Promise.resolve(userInfos); } else if (route == '/web/dataset/call_kw/lunch.order/update_quantity') { assert.equal(args.args[1], 1, 'should increment order quantity by 1'); userInfos = { ...userInfos, lines: [ { ...userInfos.lines[0], product: [1, "Big Plate", "9.9"], quantity: 2, price: 4.95 * 2, } ], total: 4.95 * 2, unpaid_subtotal: 4.95 * 2, }; return Promise.resolve(true); } } }); click(target, 'div.o_lunch_banner > .row > div:nth-child(2) button.fa-plus-circle'); }); QUnit.test("Confirm existing order", async function (assert) { assert.expect(3); let userInfos = { ...lunchInfos, lines: [ { id: 1, product: [1, "Big Plate", "4.95"], toppings: [], quantity: 1, price: 4.95, raw_state: "new", state: "To Order", note: false } ], raw_state: "new", total: "4.95", paid_subtotal: "0", unpaid_subtotal: "4.95", }; await makeLunchView({ mockRPC: (route, args) => { if (route == '/lunch/user_location_get') { return Promise.resolve(userInfos.user_location[0]); } else if (route == '/lunch/infos') { return Promise.resolve(userInfos); } else if (route == '/lunch/pay') { assert.equal(args.user_id, false); // Should confirm order of current user userInfos = { ...userInfos, lines: [ { ...userInfos.lines[0], raw_state: 'ordered', state: 'Ordered,' } ], raw_state: 'ordered', wallet: userInfos.wallet - 4.95, }; return Promise.resolve(true); } } }); const wallet = target.querySelector('.o_lunch_banner .col-9 > .d-flex > span:nth-child(2)'); assert.equal(wallet.innerText, '12.05€'); click(target, 'div.o_lunch_banner > .row > div:nth-child(3) button'); await nextTick(); assert.equal(wallet.innerText, '7.10€', 'Wallet should update'); }); }); });