/** @odoo-module **/ import FormView from 'web.FormView'; import ListView from 'web.ListView'; import testUtils from 'web.test_utils'; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; import { getFixture } from "@web/../tests/helpers/utils"; const createView = testUtils.createView; QUnit.module('fields', { beforeEach: function () { this.data = { partner: { fields: { message: {string: "message", type: "text"}, foo: {string: "Foo", type: "char", default: "My little Foo Value"}, mobile: {string: "mobile", type: "text"}, }, records: [{ id: 1, message: "", foo: 'yop', mobile: "+32494444444", }, { id: 2, message: "", foo: 'bayou', }] }, visitor: { fields: { mobile: {string: "mobile", type: "text"}, }, records: [{ id: 1, mobile: "+32494444444", }] }, }; setupViewRegistries(); this.target = getFixture(); } }, function () { QUnit.module('SmsWidget'); QUnit.test('Sms widgets are correctly rendered', async function (assert) { assert.expect(9); await makeView({ type: "form", resModel: "partner", serverData: { models: this.data }, arch: /* xml */ `
`, }); assert.containsOnce(this.target, '.o_sms_count', "Should have a sms counter"); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '0 characters, fits in 0 SMS (GSM7) ', 'Should be "0 characters, fits in 0 SMS (GSM7) " by default'); // GSM-7 await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), "Hello from Odoo", 'input'); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '15 characters, fits in 1 SMS (GSM7) ', 'Should be "15 characters, fits in 1 SMS (GSM7) " for "Hello from Odoo"'); // GSM-7 with \n => this one count as 2 characters await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), "Hello from Odoo\n", 'input'); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '17 characters, fits in 1 SMS (GSM7) ', 'Should be "17 characters, fits in 1 SMS (GSM7) " for "Hello from Odoo\\n"'); // Unicode => ê await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), "Hêllo from Odoo", 'input'); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '15 characters, fits in 1 SMS (UNICODE) ', 'Should be "15 characters, fits in 1 SMS (UNICODE) " for "Hêllo from Odoo"'); // GSM-7 with 160c var text = Array(161).join('a'); await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input'); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '160 characters, fits in 1 SMS (GSM7) ', 'Should be "160 characters, fits in 1 SMS (GSM7) " for 160 x "a"'); // GSM-7 with 161c text = Array(162).join('a'); await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input'); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '161 characters, fits in 2 SMS (GSM7) ', 'Should be "161 characters, fits in 2 SMS (GSM7) " for 161 x "a"'); // Unicode with 70c text = Array(71).join('ê'); await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input'); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '70 characters, fits in 1 SMS (UNICODE) ', 'Should be "70 characters, fits in 1 SMS (UNICODE) " for 70 x "ê"'); // Unicode with 71c text = Array(72).join('ê'); await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input'); assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '71 characters, fits in 2 SMS (UNICODE) ', 'Should be "71 characters, fits in 2 SMS (UNICODE) " for 71 x "ê"'); }); QUnit.test('Sms widgets with non-empty initial value', async function (assert) { assert.expect(1); await makeView({ type: "form", resModel: "visitor", resId: 1, serverData: { models: this.data }, arch: /* xml */ `
`, }); assert.strictEqual(this.target.querySelector('.o_field_text span').textContent, '+32494444444', 'Should have the initial value'); }); QUnit.test('Sms widgets with empty initial value', async function (assert) { assert.expect(1); await makeView({ type: "form", resModel: "partner", resId: 1, serverData: { models: this.data }, arch: /* xml */ `
`, }); assert.strictEqual(this.target.querySelector('.o_field_text span').textContent, '', 'Should have the empty initial value'); }); QUnit.module('PhoneWidget'); QUnit.test('phone field in editable list view on normal screens', async function (assert) { assert.expect(11); var doActionCount = 0; var list = await createView({ View: ListView, model: 'partner', data: this.data, debug:true, arch: '', intercepts: { do_action(ev) { assert.equal(ev.data.action.res_model, 'sms.composer', 'The action to send an SMS should have been executed'); doActionCount += 1; } } }); assert.containsN(list, 'tbody td:not(.o_list_record_selector)', 4); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yopSMS', "value should be displayed properly with a link to send SMS"); assert.containsN(list, 'div.o_field_widget.o_form_uri.o_field_phone > a', 2, "should have the correct classnames"); // Edit a line and check the result var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); await testUtils.dom.click($cell); assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode'); assert.strictEqual($cell.find('input').val(), 'yop', 'should have the corect value in internal input'); await testUtils.fields.editInput($cell.find('input'), 'new'); // save await testUtils.dom.click(list.$buttons.find('.o_list_button_save')); $cell = list.$('tbody td:not(.o_list_record_selector)').first(); assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore'); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'newSMS', "value should be properly updated"); assert.containsN(list, 'div.o_field_widget.o_form_uri.o_field_phone > a', 2, "should still have links with correct classes"); await testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector) .o_field_phone_sms').first()); assert.equal(doActionCount, 1, 'Only one action should have been executed'); assert.containsNone(list, '.o_selected_row', 'None of the list element should have been activated'); list.destroy(); }); QUnit.test('readonly sms phone field is properly rerendered after been changed by onchange', async function (assert) { assert.expect(4); const NEW_PHONE = '+32595555555'; const form = await createView({ View: FormView, model: 'partner', data: this.data, arch: '
' + '' + '' + '' + // onchange to update mobile in readonly mode directly '' + // readonly only, we don't want to go through write mode '' + '' + '
', res_id: 1, viewOptions: {mode: 'edit'}, mockRPC: function (route, args) { if (args.method === 'onchange') { return Promise.resolve({ value: { mobile: NEW_PHONE, // onchange to update mobile in readonly mode directly }, }); } return this._super.apply(this, arguments); }, }); // check initial rendering assert.strictEqual(form.$('.o_field_phone').text(), "+32494444444", 'Initial Phone text should be set'); assert.strictEqual(form.$('.o_field_phone_sms').text(), 'SMS', 'SMS button label should be rendered'); // trigger the onchange to update phone field, but still in readonly mode await testUtils.fields.editInput($('input[name="foo"]'), 'someOtherFoo'); // check rendering after changes assert.strictEqual(form.$('.o_field_phone').text(), NEW_PHONE, 'Phone text should be updated'); assert.strictEqual(form.$('.o_field_phone_sms').text(), 'SMS', 'SMS button label should not be changed'); form.destroy(); }); });